I have a usercontrol which I am including in my datagrid column.
But I want to hide that usercontrol on the basis of certain condition.
I tried binding the visibility of that usercontrol but that is not working.I dont know why is that happening.
<DataGrid>
... .
...
<UserControl:MyUserControl Visibility="{Binding
SomeProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataGrid>
But if I am using the same property in hiding the other controls present in the DataGrid columns.They are working and getting hide on the certain condition.
I dont know what is happening.Please help me guys.
Try to explicitly set the DataContext property of your UserControl:
<UserControl:MyUserControl DataContext="{Binding}" Visibility="{Binding
SomeProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
Otherwise show the full xaml for dataGrid.
I am quite sure that there is a binding error coming in Output or Immediate Window.
Why?
Because your control is looking for SomeProperty in the collection entity which is not present there.
That property as you suggested is available at the Page ViewModel level.
Therefore do this
<UserControl:MyUserControl
Visibility="{Binding DataContext.IsVisible,
RelativeSource={RelativeSource FindAncestor,
AncestorType=YourUserControl}" />
Since your control is nested in a DataGrid, the DataContext of your databinding is the same as your DataGrid context.
Therefore, you can either choose to bind the visibility of your element to a property of the DataGrid DataContext or bind it to a property of a relative UI parent DataContext or a prox.
I'll take the following model as example.
public class ViewModel
{
public class Foo
{
public int Id {get;set;}
public Visibility IsVisible {get;set;}
}
private IList<Foo> _fooList;
public IList<Foo> FooList {get;set;}
private Visibility _parentVisibility;
public Visibility ParentVisibility{get;set}
}
Solution 1 (DataGrid datacontext) :
Assuming your datagrid is bound to FooList you can straight forward bind to the IsVisible property of you Foo object as :
<UserControl:MyUserControl Visibility="{Binding IsVisible}" />
Solution 2 (Parent context) :
If you want to bind the visibility of your UserControl to a property that is not in the datagrid context you either have to specify a RelativeSource to your binding or a DataContextProxy.
Going for the RelativeSource solution you can bind the visibility of your UserControl to the ParentVisibility property as :
<UserControl:MyUserControl Visibility="{Binding DataContext.ParentVisibility, RelativeSource={RelativeSource FindAncestor, AncestorType=YourPageUserControl}" />
Hope this helps.
Related
I have a user control that defines a dependecy property to can use communicate with another user control.
This dependency propperty is in the code behind.
In this user control I have a combobox, from which I want to notify the selected item to the second user control.
The code of the first user control:
public static readonly DependencyProperty TipoComponenteSeleccionadoProperty =
DependencyProperty.Register("TipoComponenteSeleccionado", typeof(TiposComponentes),
typeof(ucClasificacionesComponentesBaseView), new PropertyMetadata(null));
public bool TipoComponenteSeleccionado
{
get
{
return (bool)GetValue(TipoComponenteSeleccionadoProperty);
}
set
{
SetValue(TipoComponenteSeleccionadoProperty, value);
}
}
I was trying something like that in the xaml:
<ComboBox Name="cmbTiposComponentes" Width="150"
TipoComponenteSeleccionado="{Binding ElementName=cmbTiposComponentes, Path=SelectedItem}">
The idea is when I select the item in the combobox, update the dependency property, so the second user control can bind it and be notified.
But I get an errror because the dependency property can't be used in the combobox.
So I was wondering if there is some way to use the dependency property in the combobox.
I have tried to define a static resource in the xaml of the first user control, something like that:
<UserControl.Resources>
<local:MyMainUserControl.DependencyProperty Key.../>
</UserControl.Resources>
But the itellisense shows me all the views that I have except this, so I don't have access to the depedency property of the view.
So is it possible to use the dependency property in the view in which it is defined?
Thanks.
bind SelectedItem to TipoComponenteSeleccionado:
<ComboBox Name="cmbTiposComponentes" Width="150"
SelectedItem="{Binding Path=TipoComponenteSeleccionado, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:TiposComponentes}}}">
I have a usercontrol, and there is a Datacontext set for it. This usercontrol contains also a Dependency-Property. Now, i want simply bind to this property.
I think the problem has something to do with the wrong datacontext.
The dependency-Property in my usercontrol (called TimePicker) looks like this:
public TimeSpan Time
{
get { return (TimeSpan)GetValue(TimeProperty); }
set
{
SetValue(TimeProperty, value);
OnPropertyChanged();
}
}
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof (TimeSpan), typeof (TimePicker));
I try to use it like this:
<upDownControlDevelopement:TimePicker Grid.Row="1" Time="{Binding Path=TimeValue}" />
When i do this i get the following binding error:
System.Windows.Data Error: 40 : BindingExpression path error: 'TimeValue' property not found on 'object' ''TimePicker' (Name='TimePickerControl')'. BindingExpression:Path=TimeValue; DataItem='TimePicker' (Name='TimePickerControl'); target element is 'TimePicker' (Name='TimePickerControl'); target property is 'Time' (type 'TimeSpan')
Any help would be highly appreciated
Greetings Michael
PS: you can download the code at here
Although this has now been solved there seems to be some, in my opinion, inappropriate use of the DataContext.
When developing a custom reusable control, you should not set DataContext at all. What the DataContext will be, that is for the user of the control to decide, not for the developer. Consider the following common pattern of code:
<Grid DataContext="{Binding Data}">
<TextBox Text="{Binding TextValue1}" />
<!-- Some more controls -->
</Grid>
Notice that here, you are using the Grid control. The developer of the control (in this case, the WPF team), didn't touch the DataContext at all - that is up to you. What does it mean for you as a control developer? Your DependencyProperty definition is fine, but you shouldn't touch the DataContext. How will you then bind something inside your control to the DependencyProperty value? A good way is using a template (namespaces omitted):
<MyTimePicker>
<MyTimePicker.Template>
<ControlTemplate TargetType="MyTimePicker">
<!-- Stuff in your control -->
<TextBlock Text="{TemplateBinding Time}" />
<TextBox Text="{Binding Time, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
<MyTimePicker.Template>
</MyTimePicker>
Note that TemplateBinding is always one-way only, so if you need any editing at all, you need to use normal binding (as you can see on the TextBox in the example).
This only means that the TextBlock/Box inside your control will get its Time value from your custom control itself, ignoring any DataContext you might have set.
Then, when you use the control, you do it like this (added to my first example):
<Grid DataContext="{Binding Data}">
<TextBox Text="{Binding TextValue1}" />
<!-- Some more controls -->
<MyTimePicker Time="{Binding TimeValue}" />
</Grid>
What just happened here is that the MyTimePicker does not have DataContext set anywhere at all - it gets it from the parent control (the Grid). So the value goes like this: Data-->(binding)-->MyTimePicker.Time-->(template binding)-->TextBlock.Text.
And above all, avoid doing this in the constructor of your custom control:
public MyTimePicker()
{
InitializeComponent();
DataContext = this;
}
This will override any DataContext set in XAML, which will make binding a huge pain (because you'll have to always set Source manually). The previous example would not work, and this wouldn't work either:
<MyTimePicker DataContext="{Binding Data}" Time="{Binding TimeValue}" />
You would think this is OK, but the DataContext will be resolved in the InitializeComponent() call, so the value will be immediately overwritten. So the binding to TimeValue will look for it in the control instead (which will, of course, fail).
Just don't touch the DataContext when developing a control and you'll be fine.
You don't need to override the data context of user control. You can use RelativeSource to point your binding source property i.e. TimeValue to any other source you like. E.g. If you have the source property in your window's class. You could simply point your binding target to the source in window's data context as follows:
{Binding Path=DataContext.TimeValue, RelativeSource={ RelativeSource AncestorType={x:Type Window}}}
Your error states that 'TimeValue' property not found on 'object' 'TimePicker', which means that the WPF Framework is looking at the 'TimePicker' object to resolve the 'TimeValue' property value. You must have somehow set the DataContext of the Window or UserControl that contains the 'TimePicker' object to an instance of the 'TimePicker' object.
Instead, it should be set to an instance of the class that declares the 'TimeValue' property. If you're using a view model, then you should set it to an instance of that:
DataContext = new YourViewModel();
If the 'TimeValue' property is declared in the Window or UserControl then you can set the DataContext to itself (although generally not recommended):
DataContext = this;
Please note that when data binding to the 'Time' property from inside your TimePicker control, you should use a RelativeSource Binding:
<TextBlock Text="{Binding Time, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:TimePicker}}}" ... />
Normally we are not setting datacontext directly.If u want to set datacontext create an instance of your usercontrol and set datacontext individually to each one.
I have a UserControl who's DataContext is being set to an instance of a ViewModel (using MVVM). But, I have controls within the UserControl which need to be bound to properties that only pertain to the view (which is why I placed them in code behind). I'm not sure how to bind this in xaml appropriately:
Note: SelectedOrderType is a property on the View-Model, and OrderTypes is a property on the UserControl itself.
<UserControl x:Class="MyNamespace.OrderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="OrderUserControl">
<Grid>
...
<ComboBox ItemsSource="{Binding Path=OrderTypes, ElementName=OrderUserControl}"
SelectedValue="{Binding Path=SelectedOrderType}"
SelectedValuePath="OrderTypeCode"
DisplayMemberPath="OrderTypeName" />
</Grid>
</UserControl>
public partial class OrderControl : UserControl
{
public OrderControl()
{
InitializeComponent();
OrderTypes = ...;
}
public IReadOnlyCollection<OrderTypeInfo> OrderTypes { get; private set; }
}
Also, I know I can simply create a property on the View-Model, and I get that some people would suggest that that would be the correct place to put it... but I really would like to know how I could do what I'm attempting to do if not for this scenario, maybe for other scenarios in the future?
I may be wrong but would you not need to make a dependency property on your user control for "SelectedOrderType" and bind the the View Model to that property not bind directly to the view model from the user control.
That way your UserControl is not dependent on the view model?
Edit:
I think you could set it up the way you have it, but the binding for SelectedOrderType would need to be something like {Binding Path=DataContext.SelectedOrderType, ElementName=OrderUserControl}
I have an MVVM Application and want to add a ContextMenu.
I added the ContextMenu to XAML and then set the Items like this (only one item here because it doesn'T matter):
<MenuItem Header="{x:Static Monitor:MonitorResources.R0206_SaveLatestValueToDatabase}"
IsCheckable="true"
IsChecked="{Binding ElementName=root, Path=Model.SaveToDbOneChecked}"
IsEnabled="{Binding ElementName=root, Path=Model.SaveToDbOneEnabled}">
The SaveToDbOneChecked and SaveToDbOneEnabled are Properties in my Model which are implemented like this:
private bool mSaveToDbOneEnabled;
public bool SaveToDbOneChecked
{
get { return mSaveToDbOneChecked; }
set { mSaveToDbOneChecked = value; OnPropertyChanged("SaveToDbOneChecked"); }
}
I set these before the ContextMenu gets called on the SelectionChanged in the GridView the ContextMenu is in. But it won't show the Checked sign next to the text of the MenuItem although the SaveToDbOneChecked has been set to true! I don'T know where i do something wrong and hope that somebody can help me here.
A few things you have to do to make this work. First of all you cannot bind from inside a MenuItem using ElementName property since the target element is most often out of your scope.
If I understand correctly the Model is your ViewModel property, in this case all you have to do is to set it as the DataContext of the Element on which the ContextMenu is placed.
This will set the same DataContext for your MenuItem and you can bind directly to DataContext:
IsChecked="{Binding SaveToDbOneChecked, Mode=TwoWay}"
I have some UserControl, It's DataContext is binded to the ViewModel,
How to set a ViewModel's property from XAML? Is it possible?
UPD :
Sorry for being not very clear,
I'm trying to get something like this :
UserControl's DataContext is binded to ViewModel, I need to set ViewModel's property to something (let's say, UserControl's Width property).
Is it possible?
UPD2: It seems to be not possible.I know about TwoWay binding mode, etc, thing I wanted to do - to set ViewModel's property to UserControl's one
This example should be very clear
<Set Property={Binding SomePropertyOnViewModel}
Value={Binding RelativeSource={RelativeSource Self},
Path=SomePropertyOnUserControl}>
I am not sure whether I understand the question exactly.
But here is an example.
It will:
Create a view model of type ExampleViewModel inside the user control by setting the user
controls DataContext property in xaml
Create a text box in xaml and bind it to the view models
TextInViewModel string property.
Set up the usual INotifyPropertyChanged interface (this was extracted to the base class ViewModelBase)
Create the view model in xaml and set the user controls data context to it:
<UserControl x:Class="MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test"
xmlns:viewModel="clr-namespace:ViewModels">
<UserControl.DataContext>
<viewModel:ExampleViewModel/>
</UserControl.DataContext>
<StackPanel Orientation="Horizontal" >
<Label>Enter Text here: </Label>
<TextBox Text="{Binding TextInViewModel}"></TextBox>
</StackPanel>
</UserControl>
ViewModel:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
public class ExampleViewModel : ViewModelBase
{
/// <summary>
/// Property bound to textbox in xaml.
/// </summary>
public String TextInViewModel
{
get { return _textInViewModel; }
set
{
_textInViewModel= value;
RaisePropertyChanged("TextInViewModel");
}
}
private string _textInViewModel;
/// <summary>
/// Constructor.
/// </summary>
public ExampleViewModel()
{
}
}
Binding works both ways: i.e. from source (e.g. viewmodel) to target (e.g. usercontrol) and from target back to source.
You specify the direction via Mode of binding.
Following are the BindingModes:
TwoWay
OneWay
OneTime
OneWayToSource
In your case, if you want to bind width property of usercontrol to the TheWidth property of ViewModel:
Case A:
Want to bind in both directions, use Mode=TwoWay
<UserControl Width="{Binding TheWidth, Mode=TwoWay}">
<!-- your rest of code -->
</UserControl>
Case B:
Want to bind only from usercontrol to viewmodel, use Mode=OneWayToSource
<UserControl Width="{Binding TheWidth, Mode=OneWayToSource}">
<!-- your rest of code -->
</UserControl>
XAML
<UserControl.DataContext>
<vm:ViewModel/>
</UserControl.DataContext>
I prefer the ViewModel Locator approach (this is like a service locator pattern for ViewModel).
Because as soon as your ViewModel has constructor parameters, you are either tightly coupled, or you can't use the above described xaml way....
There are many ViewModel-Locator ways. One is described here using MEF and silverlight.
http://johnpapa.net/simple-viewmodel-locator-for-mvvm-the-patients-have-left-the-asylum
here is another one:
http://brendan.enrick.com/post/Wire-up-your-ViewModels-using-a-Service-Locator.aspx
Well, you bind your UI elements to them:
<UserControl Width="{Binding Path=DisplayWidth, Mode=OneWayToSource}">
<Grid>
<TextBox MinWidth=100 Text="{Binding MyProperty}"/>
</Grid>
</UserControl>
assuming a view model like this:
class ViewModel
{
public string MyProperty { get; set; }
public int DisplayWidth { get; set; }
}
Through binding my dear friend..
for example: (Assuming in your context)
If you have class "Person" and your person has a Name and SurName public property and you want to bind it to a textbox. You do the following:
<TextBox Text="{Binding Path=Name}" />
This only works if the name is your public property, it is best practice to make you object ( in this case Person) as a public property and use the Path parameter differently.
Example:
<TextBox Text="{Binding Path=Person.Name}" />
It does clutter your code way less, then to make a property in your viewmodel for every property of any object in your viewmodel.
"How to set a ViewModel's property from XAML? Is it possible?"
So, that seems to be not possible, max you can accomplish - two-way binding, which is, unfortunately not I wanted.
All in all it's rather bad design than a problem