How can I bind to content control's content property ?
I'v created custom control :
public class CustomControl
{
// Dependency Properties
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MainViewModel), new PropertyMetadata(0));
}
In ViewModel I created a property of type of this custom control :
public CustomControl CustomControl { get; set; }
In view I bind this property to content control :
<ContentControl x:Name="Custom" Content="{Binding CustomControl}"></ContentControl>
Now how can I bind to content control's content property?
<ContentControl Content="{Binding ElementName=Custom, Path=Content}" />
I'm not sure what effect this will have though. I have a suspicion it will complain about UI elements already having a parent or something similar.
Update
If I think I understand your question correctly I don't think you can do what you want using bindings. This is an alternative which adds a callback for when the content is changed so you can set the new content to the property of your VM:
class CustomControl : Control
{
static CustomControl()
{
ContentControl.ContentProperty.OverrideMetadata(typeof(CustomControl), new PropertyMetadata(null, UpdateViewModel));
}
private static void UpdateViewModel(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as CustomControl;
var viewModel = control.DataContext as MyViewModel;
viewModel.CustomControl = control;
}
}
You'll probably want some error handling in there.
Related
WPF .NET4.5
The Problem: When the ListSource dependency property on the ImageCanvas is set, only the last behavior, "MyList", actually gets updated. It is as if the last behavior overwrites all the previous bindings.
How can I have all the behaviors updated when the ListSource on the ImageCanvas is updated?
I have a custom control with a ListSource dependency property:
public class ImageCanvas : ContentControl
{
public FrameElement ListSource
{
get { return (FrameElement)GetValue(ListSourceProperty); }
set { SetValue(ListSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ListSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ListSourceProperty =
DependencyProperty.Register("ListSource", typeof(FrameElement), typeof(ImageCanvas),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(s,e) =>
{
// The ListBehavior will be called before this dependency property of ImageCanvas.
ImageCanvas ic = s as ImageCanvas;
ic.Content = ((FrameElement)e.NewValue).DataContext;
}
));
}
}
The XAML is:
<ctrl:ImageCanvas x:Name="ImageCanvas"
Grid.Column="1" Grid.Row="1" Background="Aquamarine"
Panel.ZIndex="{Binding ImageLayer.ZIndex}"
Visibility="{Binding ImageLayer.Visibility}"
>
<i:Interaction.Behaviors>
<b:ImageCanvasBehavior x:Name="MyZoom" />
<b:MovieBehavior x:Name="MyMovie" />
<b:MusicBehavior x:Name="MyMusic" />
<b:ListBehavior x:Name="MyList" />
</i:Interaction.Behaviors>
</ctrl:ImageCanvas>
Each behavior is bound to the ListSource custom property of the ImageCanvas when the ImageCanvas is loaded by the XAML.
In the behaviors:
private void IC_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
var ic = AssociatedObject as ImageCanvas;
var bindingListSource = new Binding();
bindingListSource.Source = this;
bindingListSource.Path = new PropertyPath(ListSourceProperty);
BindingOperations.SetBinding(ic, ImageCanvas.ListSourceProperty, bindingListSource);
}
public FrameElement ListSource
{
get { return (FrameElement)GetValue(ListSourceProperty); }
set { SetValue(ListSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ListSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ListSourceProperty =
DependencyProperty.Register("ListSource", typeof(FrameElement), typeof(ListBehavior), new PropertyMetadata(null,
(s,e) =>
{
var behavior = s as ListBehavior;
var ic = behavior.AssociatedObject as ImageCanvas;
if ((FrameElement)e.NewValue == (FrameElement)e.OldValue)
return;
CurrentFrame = ((FrameElement)e.NewValue).Frame;
}
));
The Problem: When the ListSource dependency property on the ImageCanvas is set, only the last behavior, "MyList", actually gets updated. It is as if the last behavior overwrites all the previous bindings.
How can I have all the behaviors updated when the ListSource on the ImageCanvas is updated?
Edit#1: To better explain, I have defined a "FrameElement" as:
public class FrameElement : UIElement
{
public object DataContext { get; set; }
public int Frame { get; set; }
public ListTypeEnum ListType { get; set; }
public string Title { get; set; }
}
The ContentControl is being used to display only one item at a time, DataTemplates in Resources are being used to implicitly change the display based on the DataContext (this works well). The DataContext may or may not have a collection, depending on what the DataContext is for the current display (hence the "Frame" number). The problem is that each behavior will need to determine if the current datacontext applies to itself--so each behavior, as listed in the XAML, needs to receive the current FrameElement when it is set on the ContentControl, i.e., the "ImageCanvas".
I hope that better explains my scenario.
TIA.
Edit#2:
If the BindingOperations are removed from the behaviors, and the XAML changed to directly bind, (see below), then all the behaviors are updated correctly! So the question now becomes, how can the XAML code be replicated correctly in the behavior to achieve the same result???
Working XAML code:
<ctrl:ImageCanvas x:Name="ImageCanvas"
Grid.Column="1" Grid.Row="1" Background="Aquamarine"
Panel.ZIndex="{Binding ImageLayer.ZIndex}"
Visibility="{Binding ImageLayer.Visibility}"
>
<i:Interaction.Behaviors>
<b:ImageCanvasBehavior x:Name="MyZoom"
ListSource="{Binding ElementName=ImageCanvas, Path=ListSource}" />
<b:MovieBehavior x:Name="MyMovie"
ListSource="{Binding ElementName=ImageCanvas, Path=ListSource}" />
<b:MusicBehavior x:Name="MyMusic"
ListSource="{Binding ElementName=ImageCanvas, Path=ListSource}" />
<b:ListBehavior x:Name="MyList"
ListSource="{Binding ElementName=ImageCanvas, Path=ListSource}" />
</i:Interaction.Behaviors>
</ctrl:ImageCanvas>
How to create/ WPF Dependency Property in UserControl?
Is it possible to create it through viewmodel?
public partial class SomeView : UserControl
{
SomeViewModel vm = new SomeViewModel(ForeColor);
public SomeView()
{
InitializeComponent();
this.DataContext = vm;
}
public Color ForeColor
{
get { return (Color)this.GetValue(ForeColorProperty); }
set { this.SetValue(ForeColorProperty, value); }
}
public static readonly DependencyProperty ForeColorProperty = DependencyProperty.Register("ForeColor", typeof(Color), typeof(SomeView));
}
and then calling the control like below doesn't work.
<local:SomeView ForeColorProperty="{Binding Foreground}"/>
You reference it as "ForeColor", not "ForeColorProperty".
<local:SomeView ForeColor="{Binding Foreground}"/>
For the above binding to work, there has to be a public property "Foreground" of type "Color" in the control's current data context.
Edit
If you want to pass the value to the view model, then you need a two-way binding:
<local:SomeView ForeColor="{Binding Foreground,Mode=TwoWay}"/>
I built a UserControl with a dependency property like this:
public MyUserContol()
{
InitializeComponent();
SelectedString = "Defalut";
}
public string SelectedString
{
get { return (string)GetValue(SelectedStringProperty); }
set { SetValue(SelectedStringProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedString. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedStringProperty =
DependencyProperty.Register("SelectedString", typeof(string), typeof(MyUserContol),
new FrameworkPropertyMetadata(OnSelectedStringPropertyChanged));
private static void OnSelectedStringPropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
(source as MyUserContol).SelectedSatringChanged();
}
When I use it, it's working fine
<UserContol:MyUserControl SelectedClient="blabla" />
but in a DataTemplate it dosn't work!
<DataGrid1:DataGrid x:Name="dg" ItemsSource="{Binding MyDataTable}">
<DataGrid1:DataGrid.Columns>
<DataGrid1:DataGridTemplateColumn SortMemberPath="[Client]" Header="Date" >
<DataGrid1:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<UserContol:MyUserControl SelectedClient="blabla" >
</DataTemplate>
</DataGrid1:DataGridTemplateColumn.CellTemplate>
</DataGrid1:DataGrid.Columns>
</DataGrid1:DataGrid>
Its not changing the value to "blabla". I know it's not working because the OnSelectedStringPropertyChanged isn't being invoked! The property stays the default value given from the constructor.
Why isn't it working?
I found it !!!
i needed to remove from the Ctor this code:
SelectedString = "Defalut";
I'm trying to develop user control with some nested properties that allows to use databinding to set it. For example, I have something like this:
// Top level control
public class MyControl : Control
{
public string TopLevelTestProperty
{
get { return (string)GetValue(TopLevelTestPropertyProperty); }
set { SetValue(TopLevelTestPropertyProperty, value); }
}
public static readonly DependencyProperty TopLevelTestPropertyProperty =
DependencyProperty.Register("TopLevelTestProperty", typeof(string), typeof
(MyControl), new UIPropertyMetadata(""));
// This property contains nested object
public MyNestedType NestedObject
{
get { return (MyNestedType)GetValue(NestedObjectProperty); }
set { SetValue(NestedObjectProperty, value); }
}
public static readonly DependencyProperty NestedObjectProperty =
DependencyProperty.Register("NestedObject", typeof(MyNestedType), typeof
(MyControl), new UIPropertyMetadata(null));
}
// Nested object's type
public class MyNestedType : DependencyObject
{
public string NestedTestProperty
{
get { return (string)GetValue(NestedTestPropertyProperty); }
set { SetValue(NestedTestPropertyProperty, value); }
}
public static readonly DependencyProperty NestedTestPropertyProperty =
DependencyProperty.Register("NestedTestProperty", typeof(string), typeof
(MyNestedType), new UIPropertyMetadata(""));
}
// Sample data context
public class TestDataContext
{
public string Value
{
get
{
return "TEST VALUE!!!";
}
}
}
...
this.DataContext = new TestDataContext();
...
XAML:
<local:mycontrol x:name="myControl" topleveltestproperty="{Binding Value}" >
<local:mycontrol.nestedobject>
<local:mynestedtype x:name="myNestedControl" nestedtestproperty="{Binding Value}" />
</local:mycontrol.nestedobject>
</local:mycontrol>
It works well for property TopLevelTestProperty, but it doesn't work for NestedTestProperty.
It seems that nested bindings do not work. Can anybody help me please? Is there any way to make such binding?
I think that it happens because of my nested object has no any reference to the top level object, so it cannot be resolved using MyControl's DataContext.
H.B. right, nested control does not inherit DataContext from mycontrol.
Tyr out setting it explicitly:
<local:mycontrol x:name="myControl"
topleveltestproperty="{Binding Value}" >
<local:mycontrol.nestedobject>
<local:mynestedtype x:name="myNestedControl"
DataContext="{Binding ElementName=myControl,
Path=DataContext}"
nestedtestproperty="{Binding Value}" />
</local:mycontrol.nestedobject>
</local:mycontrol>
I am having trouble setting a property of a custom user control using a DependencyProperty through databinding on the parent UserControl.
Here is the code for my custom UserControl:
public partial class UserEntityControl : UserControl
{
public static readonly DependencyProperty EntityProperty = DependencyProperty.Register("Entity",
typeof(Entity), typeof(UserEntityControl));
public Entity Entity
{
get
{
return (Entity)GetValue(EntityProperty);
}
set
{
SetValue(EntityProperty, value);
}
}
public UserEntityControl()
{
InitializeComponent();
PopulateWithEntities(this.Entity);
}
}
I want access to the Entity property in the code behind because that will dynamically build the user control based on values stored in the Entity. The problem that I am having is that the Entity property is never set.
Here is how I am setting up the binding in the parent user control:
<ListBox Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding SearchResults}" x:Name="SearchResults_List">
<ListBox.ItemTemplate>
<DataTemplate>
<!--<views:SearchResult></views:SearchResult>-->
<eb:UserEntityControl Entity="{Binding}" ></eb:UserEntityControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am setting the ItemsSource of the ListBox to SearchResults, which is an Observable Collection of Entities (The same type as Entity on the custom UserControl).
I am not getting any runtime binding errors in the debug output window. I just cannot set the value of the Entity property. Any ideas?
You are trying to use the Entity property in the c-tor, which is too soon. the c-tor is going to be fired BEFORE the property value is going to be given.
What u need to do is to add a propertyChanged Event HAndler to the DependencyProperty, like so:
public static readonly DependencyProperty EntityProperty = DependencyProperty.Register("Entity",
typeof(Entity), typeof(UserEntityControl), new PropertyMetadata(null, EntityPropertyChanged));
static void EntityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myCustomControl = d as UserEntityControl;
var entity = myCustomControl.Entity; // etc...
}
public Entity Entity
{
get
{
return (Entity)GetValue(EntityProperty);
}
set
{
SetValue(EntityProperty, value);
}
}