I am pretty sure I am doing something dreadfully wrong, but can't figure it out.
I created a simple wrapper around a class and added a dependency property so I could bind to it. However, the binding gives no errors, but does nothing.
In order to simplify things I changed the class to TextBox, and got the same results.
public class TextEditor : TextBox
{
#region Public Properties
#region EditorText
/// <summary>
/// Gets or sets the text of the editor
/// </summary>
public string EditorText
{
get
{
return (string)GetValue(EditorTextProperty);
}
set
{
//if (ValidateEditorText(value) == false) return;
if (EditorText != value)
{
SetValue(EditorTextProperty, value);
base.Text = value;
//if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("EditorText"));
}
}
}
public static readonly DependencyProperty EditorTextProperty =
DependencyProperty.Register("EditorText", typeof(string), typeof(TextEditor));
#endregion
#endregion
#region Constructors
public TextEditor()
{
//Attach to the text changed event
//TextChanged += new EventHandler(TextEditor_TextChanged);
}
#endregion
#region Event Handlers
private void TextEditor_TextChanged(object sender, EventArgs e)
{
EditorText = base.Text;
}
#endregion
}
When I run the following XAML the first gives results, but the second one (EditorText) doesn't even hit the EditorText property.
<local:TextEditor IsReadOnly="True" Text="{Binding Path=RuleValue, Mode=TwoWay}" WordWrap="True" />
<local:TextEditor IsReadOnly="True" EditorText="{Binding Path=RuleValue, Mode=TwoWay}" WordWrap="True" />
You're doing extra work in your CLR property. There is no guarantee that your CLR property will be used by WPF so you shouldn't be doing this. Instead, use metadata on your DP to achieve the same effect.
public string EditorText
{
get { return (string)GetValue(EditorTextProperty); }
set { SetValue(EditorTextProperty, value); }
}
public static readonly DependencyProperty EditorTextProperty =
DependencyProperty.Register(
"EditorText",
typeof(string),
typeof(TextEditor),
new FrameworkPropertyMetadata(OnEditorTextChanged));
private static void OnEditorTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var textEditor = dependencyObject as TextEditor;
// do your extraneous work here
}
Related
I've been using code like this
<ComboBox ItemsSource="{Binding Path=CompaniesViewModel.CompaniesCollection}"
SelectedValuePath="CompanyId"
SelectedValue="{Binding Path=CompanyId}"
IsEnabled="False"
DisplayMemberPath="CompanyName"
/>
To display a Company Name in a ComboBox. Notice how the IsEnabled is set to false...that's because I really don't want the user to use the ComboBox. I am just using it as an easy way to convert an ID to string for display purposes.
When I put items in a Grid and there are a lot of them, I think it is really hurting the rendering performance. When I remove the ComboBox it loads in a split second. When the ComboBox is used in the code it can take 20 seconds.
I guess my question is I think I should be using a Label or TextBlock but not sure how to get the binding to work correctly as They don't have an ItemsSource or a SelectedValuePath or SelectedValue.
I thought about writing an IValueConverter but not sure how to bind/pass in the 3 values. I'd have to pass in the collection, the ValuePath and the Value ID.
Any thoughts or suggestions?
Put a
public Company Company {get {return CompaniesCollection.FirstOrDefault(x => x.CompanyId == CompanyId); }}
property in the ViewModel.
I welcome any of you to examine my code to see if you can make it more efficient but this is what I ended up doing.
<cc:LookupLabel
ItemsSource="{Binding Path=CompaniesCollection}"
SelectedValuePath="CompanyId"
SelectedValue="{Binding Path=CompanyId}"
DisplayMemberPath="CompanyName"
/>
And below is the LookupLabel derived from Label and INotifyPropertyChanged. I'm not sure how Microsoft implements this efficiently but this was my best stab at it. In particular the GetContent method listed at the bottom. All the other stuff is just the messy DependencyProperty declarations.
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace CustomControls
{
public class LookupLabel : Label, INotifyPropertyChanged
{
public LookupLabel()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#region ItemsSource
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(LookupLabel)
, new UIPropertyMetadata(null, LookupLabel.ItemsSourceChanged)
);
private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LookupLabel t = d as LookupLabel;
t.NotifyPropertyChanged("ItemsSource");
t.Content = GetContent(t);
}
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
#endregion ItemsSource
#region SelectedValue
public static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(LookupLabel)
, new UIPropertyMetadata(null, LookupLabel.SelectedValueChanged)
);
private static void SelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LookupLabel t = d as LookupLabel;
t.NotifyPropertyChanged("SelectedValue");
t.Content = GetContent(t);
}
[Localizability(LocalizationCategory.NeverLocalize)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Bindable(true)]
[Category("Appearance")]
public object SelectedValue
{
get
{
return (object)GetValue(SelectedValueProperty);
}
set
{
SetValue(SelectedValueProperty, value);
}
}
#endregion SelectedValue
#region SelectedValuePath
public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(LookupLabel)
, new UIPropertyMetadata(string.Empty, LookupLabel.SelectedValuePathChanged)
);
private static void SelectedValuePathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LookupLabel t = d as LookupLabel;
t.NotifyPropertyChanged("SelectedValuePath");
t.Content = GetContent(t);
}
[Localizability(LocalizationCategory.NeverLocalize)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Bindable(true)]
[Category("Appearance")]
public string SelectedValuePath
{
get
{
return (string)GetValue(SelectedValuePathProperty);
}
set
{
SetValue(SelectedValuePathProperty, value);
}
}
#endregion SelectedValuePath
#region DisplayMemberPath
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(LookupLabel)
, new UIPropertyMetadata(string.Empty, LookupLabel.DisplayMemberPathChanged)
);
private static void DisplayMemberPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LookupLabel t = d as LookupLabel;
t.NotifyPropertyChanged("DisplayMemberPath");
t.Content = GetContent(t);
}
[Localizability(LocalizationCategory.NeverLocalize)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Bindable(true)]
[Category("Appearance")]
public string DisplayMemberPath
{
get
{
return (string)GetValue(DisplayMemberPathProperty);
}
set
{
SetValue(DisplayMemberPathProperty, value);
}
}
#endregion DisplayMemberPath
protected static object GetContent(LookupLabel label)
{
if (label.ItemsSource == null)
{
return null;
}
if (string.IsNullOrWhiteSpace(label.SelectedValuePath))
{
return null;
}
if (string.IsNullOrWhiteSpace(label.DisplayMemberPath))
{
return null;
}
if (label.SelectedValue == null)
{
return null;
}
object result = null;
System.Reflection.PropertyInfo valuePropertyInfo = null;
foreach (var item in label.ItemsSource)
{
if (valuePropertyInfo == null)
{
valuePropertyInfo = item.GetType().GetProperty(label.SelectedValuePath);
if (valuePropertyInfo == null)
{
return null;
}
}
if (valuePropertyInfo.GetValue(item, null).Equals(label.SelectedValue))
{
var displayPropertInfo = item.GetType().GetProperty(label.DisplayMemberPath);
if (displayPropertInfo == null)
{
return null;
}
else
{
result = displayPropertInfo.GetValue(item, null);
break;
}
}
}
return result;
}
}
}
I am guessing that your combobox is taking too long to load because your collection has a lot of items.
You shouldn't be loading all your companies if you'll just show one of them, as a general good-practice.
I don't quite grasp your intent in using the combobox. Is it the style? can it be enabled in the future?
If it is only an easy way of displaying the CompanyName then i'd suggest the following:
Bind directly to CompanyName property.
-OR-
in the code-behind, create a calculated property named "CompanyDisplayName" that gets your company name.
Bind to it in the XAML
in the code-behind, whenever the current selected Company instance or the CompanyId changes fire 'OnPropertyChanged("CompanyDisplayName")
Try a TextBlock or a readonly TextBox to enable copy/paste;
For more info on the NotifyPropertyCahnged paradigm read here
I am trying to create a composite DataContext for a UserControl. Basically I have a control which has Order and Package properties and I wanted to create the composite object representing this datasource in XAML rather than in code.
This is how I am trying to display the UserControl (and create the DataContext):
<views:PackageDetailsControl>
<views:PackageDetailsControl.DataContext>
<vm:OrderPackagePair Package="{Binding Package, Mode=OneWay}"
Order="{Binding Order, Mode=OneWay}"/>
</views:PackageDetailsControl.DataContext>
</views:PackageDetailsControl>
The OrderPackagePair object is a simple dependency object that is created in XAML :
public class OrderPackagePair : DependencyObject
{
public OrderDetails Order
{
get { return (OrderDetails)GetValue(OrderProperty); }
set { SetValue(OrderProperty, value); }
}
public static readonly DependencyProperty OrderProperty =
DependencyProperty.Register("Order", typeof(OrderDetails), typeof(OrderPackagePair), new UIPropertyMetadata(null));
public PackageInfo Package
{
get { return (PackageInfo)GetValue(PackageProperty); }
set { SetValue(PackageProperty, value); }
}
public static readonly DependencyProperty PackageProperty =
DependencyProperty.Register("Package", typeof(PackageInfo), typeof(OrderPackagePair), new UIPropertyMetadata(null));
}
Order and Package are not bound correctly and are just null.
Yes I know there's probably a better way of doing this - but I cannot understand why this isn't working. Occasionally in Blend it'll work and then go blank again.
This will not work because DependencyObject(OrderPackagePair class) doesn't monitor internal changes of its dependency properties. As OrderPackagePair object remains the same, DataContext considered as unchanged.
On the opposite site, class Freezable is intented to notify subscribers that instance was changed when one of its dependency properties changed.
So, try to declare Freezable instead of DependencyObject as base class of OrderPackagePair.
------------- UPDATE --------
Yes, it works. In order to prove it I've implemented simple example.
Code of OrderPackagePairClass:
public class OrderPackagePair : Freezable
{
public OrderDetails Order
{
get { return (OrderDetails)GetValue(OrderProperty); }
set { SetValue(OrderProperty, value); }
}
public static readonly DependencyProperty OrderProperty =
DependencyProperty.Register("Order", typeof(OrderDetails), typeof(OrderPackagePair), new UIPropertyMetadata(null));
public PackageInfo Package
{
get { return (PackageInfo)GetValue(PackageProperty); }
set { SetValue(PackageProperty, value); }
}
public static readonly DependencyProperty PackageProperty =
DependencyProperty.Register("Package", typeof(PackageInfo), typeof(OrderPackagePair), new UIPropertyMetadata(null));
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}
XAML:
<Window x:Class="WindowTest.MainWindow"
xmlns:self="clr-namespace:WindowTest"
Name="RootControl">
<StackPanel Margin="10" DataContextChanged="StackPanel_DataContextChanged">
<StackPanel.DataContext>
<self:OrderPackagePair Package="{Binding Path=DataContext.PackageInfo, Mode=OneWay, ElementName=RootControl}"
Order="{Binding Path=DataContext.OrderDetails, Mode=OneWay, ElementName=RootControl}"/>
</StackPanel.DataContext>
<Button Margin="10" Content="Change Package" Click="Button_Click"/>
</StackPanel>
</Window>
And code behind:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private OrderDetails _orderDetails;
public OrderDetails OrderDetails
{
get
{
return this._orderDetails;
}
set
{
this._orderDetails = value;
this.OnPropertyChanged("OrderDetails");
}
}
private PackageInfo _packageInfo;
public PackageInfo PackageInfo
{
get
{
return this._packageInfo;
}
set
{
this._packageInfo = value;
this.OnPropertyChanged("PackageInfo");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.PackageInfo = new PackageInfo(DateTime.Now.ToString());
}
private void StackPanel_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("StackPanel.DataContext changed");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
var safeEvent = this.PropertyChanged;
if (safeEvent != null)
{
safeEvent(this, new PropertyChangedEventArgs(name));
}
}
}
When you click the button, model changes PackageInfo property (for simplicity model and view are implemented in the same class). Dependency property OrderPackagePair.Package reacts on new value and overwrites its value. Due to Freezable nature, OrderPackagePair notifies all subscribers that it was changed and handler StackPanel_DataContextChanged is called. If you get back to DependencyObject as base class of OrderPackagePair - handler will be never called.
So, I suppose your code doesn't work because of other mistakes. You should carefully work with DataContext. For example, you wrote:
<views:PackageDetailsControl>
<views:PackageDetailsControl.DataContext>
<vm:OrderPackagePair Package="{Binding Package, Mode=OneWay}"
Order="{Binding Order, Mode=OneWay}"/>
</views:PackageDetailsControl.DataContext>
</views:PackageDetailsControl>
and certainly this is one of the problems. Binding expression is oriented on current DataContext. But you set DataContext as OrderPackagePair instance. So you binded OrderPackagePair.Package to OrderPackagePair.Package (I suppose, that your goal is to bind OrderPackagePair.Package to Model.Package). And that's why nothing happened.
In my example in binding expression I explicitly tell to which DataContext I want to bind:
Package="{Binding Path=DataContext.PackageInfo, Mode=OneWay, ElementName=RootControl}"
Suppose I have usercontrol with textbox, combobox, button,... inside this control.
Button1 is bound to a ICommand in view model.
My request is: when user hit Enter key in any field, like any textbox, combobox, it will fire Button1 Click event, so that ICommand will be called.
How to implement this?
I created simple behaviour for this kind of situation
<TextBox Grid.Row="2" x:Name="Tags">
<i:Interaction.Behaviors>
<this:KeyEnterCommand Command="{Binding AddTagsCommand}" CommandParameter="{Binding ElementName=Tags}" />
</i:Interaction.Behaviors>
</TextBox>
behaviour code:
public class KeyEnterCommand : Behavior<Control>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.KeyDown += KeyDown;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.KeyDown -= KeyDown;
}
void KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter && Command != null)
{
Command.Execute(CommandParameter);
}
}
#region Command (DependencyProperty)
/// <summary>
/// Command
/// </summary>
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(KeyEnterCommand),
new PropertyMetadata(null));
#endregion
#region CommandParameter (DependencyProperty)
/// <summary>
/// CommandParameter
/// </summary>
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(KeyEnterCommand),
new PropertyMetadata(null));
#endregion
}
Add a dependency property to the UserControl:-
public ICommand EnterKeyCommand
{
get { return GetValue(EnterKeyCommandProperty) as ICommand; }
set { SetValue(EnterKeyCommandProperty, value); }
}
public static readonly DependencyProperty EnterKeyCommandProperty =
DependencyProperty.Register(
"EnterKeyCommand",
typeof(ICommand),
typeof(MyControl),
null);
Attach a handler for the Keyup event on the UserControl using the AddHandler method:-
void MyControl()
{
InitializeComponent();
this.AddHandler(UIElement.KeyUpEvent, new KeyEventHandler(UserControl_KeyUp), true); //Note that last parameter important
}
void UserControl_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && EnterKeyCommand != null && EnterKeyCommand.CanExecute(null))
{
EnterKeyCommand.Execute(null);
}
}
Note the point here is that the use of AddHandler allows you to intercept an event that has already been handled.
Also note that this is simplified for clarity. In reality you would also want to implement another dependency property for the Command parameter and pass that to CanExecute and Execute instead of null. You would also need to detect whether the OriginalSource is a TextBox that has AcceptsReturn set to true.
trying my first attached behavior: I want to bind the TextSelection of the RichTextBox to my ViewModel`s property:
public TextSelection SelectedRichText {get;set;}
That way I bind it:
<RichTextBox behavior:RichTextBoxSelectionBehavior.RichTextBoxSelection="{Binding SelectedRichText}" />
Thats my code and I have 2 questions:
1) Why is the OnRichTextBoxSelectionPropertyChanged never called?
2) see the question is this method at bottom: OnRichTextBoxGotSelectedText
public static class RichTextBoxSelectionBehavior
{
public static TextSelection GetRichTextBoxSelection(DependencyObject obj)
{
return (TextSelection)obj.GetValue(RichTextBoxSelection);
}
public static void SetRichTextBoxSelection(DependencyObject obj, TextSelection value)
{
obj.SetValue(RichTextBoxSelection, value);
}
// Using a DependencyProperty as the backing store for MyProperty.
public static readonly DependencyProperty RichTextBoxSelection =
DependencyProperty.RegisterAttached
(
"RichTextBoxSelection",
typeof(TextSelection),
typeof(RichTextBoxSelectionBehavior),
new UIPropertyMetadata(OnRichTextBoxSelectionPropertyChanged)
);
private static void OnRichTextBoxSelectionPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
RichTextBox rtb = dpo as RichTextBox;
if (rtb != null)
{
if ( !((TextSelection)args.NewValue).IsEmpty)
{
// if the TextSelected has selected text hook up the RichTextBox intenal SelectedChanged event with my own
rtb.SelectionChanged += OnRichTextBoxGotSelectedText;
}
else
{
rtb.SelectionChanged -= OnRichTextBoxGotSelectedText;
}
}
}
private static void OnRichTextBoxGotSelectedText(object sender, RoutedEventArgs e)
{
RichTextBox rtb = (RichTextBox) sender;
// How can I pass now my rtb.Selection to the property the behavior is bound to? e.g. my SelectedRichText property in the ViewModel
//Action action = () => { rtb.Selection; };
//rtb.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
}
}
I mixed up an attached behavior with a dependency property, here is the solution:
Put a RichTExtBox in a UserControl and this code too:
// SelectedText property.
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("SelectedText", typeof(TextSelection),
typeof(MyRichTextBox ));
/// <summary>
/// Default constructor.
/// </summary>
public MyRichTextBox ()
{
InitializeComponent();
this.TextBox.SelectionChanged += new RoutedEventHandler(TextBox_SelectionChanged);
}
void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
var sT = (e.OriginalSource as RichTextBox).Selection;
SelectedText = sT;
}
/// <summary>
/// The WPF Selected Text of the FlowDocument in the control
/// </summary>
public TextSelection SelectedText
{
get { return (TextSelection)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
//UserControl embedded in the MainWindow.xaml
<My:MyRichTextBox SelectedText="{Binding SelectedDocument,Mode=TwoWay}" x:Name="EditBox" />
Now you have access to the TextSelection of the richtextbox in your ViewModel!
I’m trying to achieve something that is conceptually quite simple but can’t seem to get it working.
I have a class called c1 it has 2 dependency properties in it an integer I and a string S. It implements INotifiyPropertyChanged.
public class c1: INotifyPropertyChanged
{
private int i;
public int I { get { return i; } set { i = value; if(PropertyChanged != null) PropertyChanged(this,new PropertyChangedEventArgs("I")); } }
private string s;
public string S { get { return s; } set { s = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("S")); } }
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
This class is referenced by a Silverlight user control SUC that also implements INotifiyPropertyChanged as a dependency property C, with a PropertyChangedCallback etc. As seen below.
public partial class SUC : UserControl, INotifyPropertyChanged
{
public c1 C
{
get { return (c1)GetValue(CProperty); }
set { SetValue(CProperty, value); }
}
public static readonly DependencyProperty CProperty =
DependencyProperty.Register("C", typeof(c1), typeof(SUC), new PropertyMetadata(new c1(), new PropertyChangedCallback(c1Changed)));
private static void c1Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
SUC s = obj as SUC;
if (s != null)
s.CChanged((c1)e.NewValue);
}
public void CChanged(c1 c)
{
C = c;
if(PropertyChanged!=null)
PropertyChanged(this,new PropertyChangedEventArgs("C"));
}
public SUC()
{
InitializeComponent();
this.DataContext = this;
}
private void bclick(object sender, RoutedEventArgs e)
{
C.S = C.S + " Clicked";
MessageBox.Show(C.I.ToString() + " - " + C.S);
}
public event PropertyChangedEventHandler PropertyChanged;
}
In my main page which also implements INotifiyPropertyChanged I have an instance of c1 and of SUC.
public partial class MainPage : UserControl, INotifyPropertyChanged
{
public c1 MC
{
get { return (c1)GetValue(MCProperty); }
set { SetValue(MCProperty, value); }
}
public static readonly DependencyProperty MCProperty =
DependencyProperty.Register("MC", typeof(c1), typeof(MainPage), new PropertyMetadata(new c1()));
private static void MCChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MainPage mp = d as MainPage;
if (mp != null)
mp.MCChanged();
}
public void MCChanged()
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("MC"));
}
public MainPage()
{
InitializeComponent();
MC.S = "ssss";
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
}
I want to set the C property of the SUC user control via XAML. Like so
local:SUC x:Name="suc" C="{Binding MC, Mode=TwoWay}"
This works well in the c# code behind but not in XAML. The reason I need it in XAML is because I want to bind a collection of c1’s to SUC’s in a DataTemplate.
Any working examples with downloadable code would be most appreciated.
It's a simple little bug in the constructor of the SUC class:
public SUC()
{
InitializeComponent();
this.DataContext = this; //this line shouldn't be here, delete and it will work
}
That means the DataContext of SUC control is itself instead of the MainPage class which is what it needs to be in order to bind to MainPage.MC (the SUC class doesn't have an MC property).
Also, and I realise most of these were you probably just trying to get it to work, but MC does not need to be a DP, you don't need the 'C=c;' line in the SUC, and I wouldn't use the MainPage control class as a datacontext class as well, create another class to bind the DataContext to.
The problem seems to be that you set the DataContext of the UserControl after you load the XAML. Either set it before the XAML is loaded (i.e. before InitializeComponent), or even better, set it in the XAML as such:
<local:MainPage ... DataContext="{Binding RelativeSource={RelativeSource Self}}">
....
</local:MainPage>
The RelativeSource binding specifies that the DataContext of your MainPage should be itself, which seems to be what you want. This then eliminates the assignment of DataContext in code-behind, which is always a good thing in WPF/Silverlight.
Hope that helps.
The DataContext of the UserControl's Controls can be different from the UserControl itself or the UserControl's Parent "Form" (or Parent Page, UserControl). You have to set the Binding in the Code Behind. See this post for more information: Silverlight UserControl Custom Property Binding
Also, You may want to create a Silverlight Control instead of a Silverlight UserControl