In MainWindow class I have checkbox that controls property used by many objects like grids, listviews, etc in UserControls
<CheckBox Content="Show objects ID" Name="showID" IsChecked="False" />
than there is property defined,
public Visibility ShowObjectIDasVisibility
{
get { return showID.IsChecked.Equals(true) ? Visibility.Visible : Visibility.Collapsed; }
}
I have some more like this to return boolean, width depending on what should be used on target control.
I managed to bind controls located in UserControl objects to use this property like this:
<TextBlock Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=ShowObjectIDasVisibility}" />
But it works only ones, while creating this TextBlock, than I can toggle checkbox as many times I like, and the TextBlock will stay visible or not depending on first value.
How should I do this properly? Thanks.
Instead of INotifyPropertyChanged interface you can use DependencyProperty:
public Visibility ShowObjectIDasVisibility
{
get { return (Visibility)GetValue(ShowObjectIDasVisibilityProperty); }
set { SetValue(ShowObjectIDasVisibilityProperty, value); }
}
public static readonly DependencyProperty ShowObjectIDasVisibilityProperty =
DependencyProperty.Register("ShowObjectIDasVisibility", typeof(Visibility), typeof(MainWindow), new PropertyMetadata(Visibility.Collapsed));
Now, to show/hide your TextBlock you need to change ShowObjectIDasVisibility value.
For example, you can do it by adding to checkbox Click="OnShowID_Click and in code behind
private void OnShowID_Click(object sender, RoutedEventArgs e)
{
ShowObjectIDasVisibility = ShowObjectIDasVisibility == System.Windows.Visibility.Visible ? System.Windows.Visibility.Collapsed : System.Windows.Visibility.Visible;
}
if your binding is correct. you just need to make sure that your code class is implementing INotifyPropertyChanged interface in class binded to view and you are raising RaisePropertyChanged event in every checkbox state change. For more details look at example here.
Related
I have a Custom user control in a silver light Project.
I use it in other page and want to Pass textbox to Custom User control.
For this I create dependcy as below :
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("TextBoxControl", typeof(TextBox), typeof(SpellCheck), new PropertyMetadata(false));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(MyPropertyProperty); }
set
{
SetValue(MyPropertyProperty, value);
TextSpell = value;
}
}
Here TextSpell is a textbox.
And I use this property in a silver light page as below:
<TextBox x:Name="txtNote" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="400"/>
<myButton:SpellCheck x:Name="btnSpell" Grid.Row="3" TextBoxControl="txtNote" Grid.Column="1" Width="20" Height="20" Margin="403,0,0,0" HorizontalAlignment="Left"/>
But I give s me a error : "The Typeconvertor for Texbox dose not support converting from a string"
So How can I pass a text box in custom usercontrol.
Thanks,
Hitesh
You can not simply use the field name (x:Name) string of the TextBox as a value for your TextBoxControl property. Instead you may use an ElementName binding like this:
<myButton:SpellCheck TextBoxControl="{Binding ElementName=txtNote}" ... />
And there are more things wrong:
In the CLR wrappers of a dependency property, you should never call anything else than GetValue and SetValue. The explanation is given in the XAML Loading and Dependency Properties article on MSDN. Instead, you have to have a PropertyChangedCallback registered with the property metadata.
There is a naming convention for the static dependency property fields. They should be named like the property, with a trailing Property.
The default value has to match the property type. Your false value is not valid, and might be null instead. But as that is the default anyway, you should leave it out completely.
The declaration would now look like this:
public static readonly DependencyProperty TextBoxControlProperty =
DependencyProperty.Register(
"TextBoxControl", typeof(TextBox), typeof(SpellCheck),
new PropertyMetadata(TextBoxControlPropertyChanged));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(TextBoxControlProperty); }
set { SetValue(TextBoxControlProperty, value); }
}
private static void TextBoxControlPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var spellCheck = (SpellCheck)obj;
spellCheck.TextSpell = (TextBox)e.NewValue;
}
I have a WPF user control that has a DependencyProperty called IsMultiSelect. I want to show hide a Button in the UserControl xaml.
<Button Visibility="{Binding IsMultiSelect, Converter=....}" />
This user control has a ViewModel assigned to the DataContext.
The above syntax gives me a binding error due to the property not existing in the view model.
How can I fix this error?
You can target the UserControl in different ways in the binding.
One solution would be to find it by setting a RelativeSource like this:
<Button Visibility="{Binding IsMultiSelect,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}},
Converter=....}" />
Instead of binding to the property from xaml, the property changed handler for the dependency property should change the button's visibility.
public static readonly DependencyProperty IsMultiSelectProperty = DependencyProperty.Register("IsMultiSelect", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false, OnIsMultiSelectPropertyChanged));
private static void OnIsMultiSelectPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
(sender as MyUserControl).OnIsMultiSelectPropertyChanged(e);
}
private void OnIsMultiSelectPropertyChanged(DependencyPropertyChangedEventArgs e)
{
MyButton.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;
}
public bool IsMultiSelect
{
get { return (bool)GetValue(IsMultiSelectProperty); }
set { SetValue(IsMultiSelectProperty, value); }
}
And you can put the converter logic inside OnIsMultiSelectPropertyChanged as well.
I have a little problem here. I've created custom TreeView using RadTreeView. It all works nice, but I've encountered an obstacle. I've set DependencyProperty for SelectedItem in TreeView. I nest my control in View, bind property to SelectedItem in TwoWay mode, but bound property won't update, it's null all the time, despite DependencyProperty value being set.
Here's tree xaml:
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:sdk='http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'
xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' x:Name='this' >
<Grid.Resources>
<DataTemplate x:Key='ChildTemplate'>
<TextBlock Text='{Binding Path=ChildPath}' Margin='5,0' />
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key='NameTemplate' ItemsSource='{Binding ChildrenCollectionPath}' ItemTemplate='{StaticResource ChildTemplate}'>
<TextBlock Text='{Binding Path=ParentPath }' Padding='7'/>
</telerik:HierarchicalDataTemplate>
</Grid.Resources>
<telerik:RadTreeView x:Name='rtvTreeView' Padding='5' BorderThickness='0' IsEditable='False' IsLineEnabled='True' IsExpandOnDblClickEnabled='False' ItemTemplate='{StaticResource NameTemplate}' />
</Grid>
Below is way I nest the control in View:
<windows:TreeViewReuse CollectionSource="{Binding SitesCollectionWithAddress}" ParentPath="Napis" Grid.Column="0" BorderThickness="2" SelectedItemD="{Binding SelectedSide, ElementName=this, UpdateSourceTrigger=Explicit, Mode=TwoWay}" ChildPath="FullAddress" ChildrenCollectionPath="AdresyStrony" BorderBrush="Red" DoubleClickCommand="{Binding TreeViewDoubleClick}">
</windows:TreeViewReuse>
And here's Tree's code behind in parts:
public partial class TreeViewReuse : UserControl
{
static Telerik.Windows.FrameworkPropertyMetadata propertyMetaData = new Telerik.Windows.FrameworkPropertyMetadata(null,
Telerik.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(SelectedItemChangedCallback));
public object SelectedItemD
{
get { return GetValue(SelectedItemDProperty); }
set { SetValue(SelectedItemDProperty, value); }
}
public static readonly DependencyProperty SelectedItemDProperty =
DependencyProperty.Register("SelectedItemD", typeof(object), typeof(TreeViewReuse), propertyMetaData);
public TreeViewReuse()
{
InitializeComponent();
Loaded += new RoutedEventHandler(TreeViewReuse_Loaded);
}
void treeView_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
SelectedItemD = _treeView.SelectedItem;
}
static private void SelectedItemChangedCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
}
Does anyone have an idea why property bound to SelectedItemD does not update? I don't care about setting tree's selected item from it, I only want to set it to selected item.
Here's property:
public StronaSprawy SelectedSide
{
get
{
return _selectedSide;
}
set
{
_selectedSide = value;
}
}
Your Dependency Property looks fine.. all except for that Telerik.Windows.FrameworkPropertyMetadata instance.
Silverlight does not support setting meta data options, so I cant think how the Telerik implementation will achieve that. It is possible that Telerik have their own DP implementation, or even that this type of property meta data only works with their controls.
Try using the standard System.Windows.PropertyMetaData type instead and see if that works for you.
I am relatively new to WPF, XAML and Data-bindings. I have a view (Window) and a view-model.
I have tried to implement the MVVM pattern which means neither the view nor the view-model hold a reference to each other. All data exchange happens via data-bindings.
So far so good but now I have run into a problem I can't find a solution for.
On my view I have a button Start which is bound to a command.
<Button Command="{Binding NextCommand}" Content="Next">
NextCommand is of type ActionCommand : ICommand
In my case NextCommand simply calls a private method within the view-model.
The problem I can not find a solution so far is the following:
How to close the window at the end of the view-models NextCommandAction method?
private void NextCommandAction(object o)
{
...
...
// close the window
}
Since I do not have a reference to the view I can not just set DialogResult = true;
The only working solution I have found so far is to add a hidden radio-button to the view and bind it's value to a property CloseView and create a method CloseView within the xaml.cs file which is bound to the Checked event of the hidden radio-button. Within that method I set DialogResult = true;
Although this works I feel like there has to be a better solution than adding hidden elements to your view!
You can pass the window reference as CommandParameter to the Close command and do whatever required on the window.
<Button Content="Close" Command="{Binding Path=CloseCommand}"
CommandParameter="{Binding ElementName=Window}"/>
private void CloseCommand(object sender)
{
Window wnd = sender as Window;
wnd.Close();
}
CommandParameter="{Binding ElementName=Window}" assumes that you have an element in your XAML named "Window". e.g, your Window tag would need Name="Window"
This question was one of the first things that came up when I googled to check if DialogResult is a dependency property (it isn't :-) )
Add a dependency property to your Window:
public static readonly DependencyProperty InteractionResultProperty =
DependencyProperty.Register(
nameof(InteractionResult),
typeof(Boolean?),
typeof(MyWpfWindow1),
new FrameworkPropertyMetadata(default(Boolean?),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnInteractionResultChanged));
public Boolean? InteractionResult
{
get => (Boolean?) GetValue(InteractionResultProperty);
set => SetValue(InteractionResultProperty, value);
}
private static void OnInteractionResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyWpfWindow1) d).DialogResult = e.NewValue as Boolean?;
}
I named my property InteractionResult though a good name would have also worked.
In the xaml right after the
you can bind it with a style
<Window.Style>
<Style TargetType="{x:Type z:MyWpfWindow1}">
<Setter Property="InteractionResult"
Value="{Binding UpdateResult}" />
</Style>
</Window.Style>
UpdateResult is the property in my viewmodel.
private Boolean? _updateResult;
public Boolean? UpdateResult
{
get => _updateResult;
set => SetValue(ref _updateResult, value);
}
The SetValue method is the usual notify property
protected virtual Boolean SetValue<T>(ref T field, T value,
[CallerMemberName]String propertyName = null)
{
if (Equals(field, value))
return false;
field = value;
RaisePropertyChanged(propertyName);
return true;
}
and the property gets set in the usual way
<Button Content="Cancel"
Command="{Binding CancelCommand}" />
ICommand CancelCommand { get; }
private void OnCancel()
{
UpdateResult = false;
}
Disclaimer: works on my computer.
Inspired by Chandrashekhar Joshi's answer
(but not using the elements's name):
Define CommandParameter in Button:
<Button
Command="{Binding CloseCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Content="Close" />
Define Command (and Implementation):
CloseCommand = new DelegateCommand<Window>((w) => w.DialogResult = true);
What do I need to add to set a public property on my ViewModel instance from my View? I'd like to set some properties on the ViewModel resource rather than bind it from some element in my view.
View XAML:
<UserControl.Resources>
<vm:MainViewModel x:Key="mainViewModel" MyProperty="30" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source={StaticResource mainViewModel}" />
</UserControl.DataContext>
MainViewModel.cs (implements INotifyPropertyChanged)
private int _myProperty;
public int MyProperty{
get { return _myProperty; }
set
{
_myProperty = value;
OnPropertyChanged("MyProperty");
}
}
The setter on MyProperty is never called. There must be some fundamental MVVM thing i'm doing wrong.
Normally you would create a binding which binds the property on the ViewModel with a property of a control. For example you could bind MyProperty to a textbox like so:
<TextBox Text="{Binding MyProperty}" />
Since the parent data context specified by UserControl.DataContext is an instance of MainViewModel, this binding will bind to a property of that object.
Well what you can do is set the MouseDown of a control such as a 'save' button on a method of the code-behind of your view. Then in the codebehind, you set your ViewModel's property or call his method.
In your View.xaml.cs you need something like this
private MyViewModele myVM;
public MyView()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Initialized); //After loading, call Initialized(...)
}
private void Initialized(object sender, RoutedEventArgs e)
{
myVM= this.DataContext as MyViewModele ; //Reference to your ViewModel
}
private void Label_General(object sender, RoutedEventArgs e)
{
myVM.Property = "w/e"; //Set the ViewModel property
}
In your View.xaml
<Label
Content="Click this label"
MouseDown="Label_General"
>
</Label>
Here i setted the Property to a static string but you can retrive any of your View's control and use its value to push it in your ViewModel.
I hope this answer your question.
My psuedo code above actually works. I had another issue with my ViewModel's constructor which had me stumped.