Data Binding in UWP User Controls using Template 10 - c#

I cannot get binding to work in my app with a user control. It is a UWP app with template 10.
I use the same bind in the mainpage as I do in the user control but the field in the user control does not react to changes. I have read several articles that tell me how to set the datacontent of my user control but I can not get any of them to work.
My code is as follows:
Mainpage.xaml
Page x:Class="UserControlTest.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:UserControlTest.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:UserControlTest.ViewModels" mc:Ignorable="d">
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:PageHeader x:Name="pageHeader" Content="Main Page"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True" />
<TextBlock x:Name="mainTextBlock" Margin="16,16,16,16"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.Below="pageHeader"
Text="{Binding TextToShow}" />
<local:ShowText Margin="16,16,16,16"
RelativePanel.Below="pageHeader"
RelativePanel.AlignRightWithPanel="True"/>
<Button Content="Change Text" Margin="16,16,16,16"
Command="{x:Bind ViewModel.ChangeText }"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.Below="mainTextBlock"/>
</RelativePanel>
</Page>
MainPageViewModel.cs
using System.Collections.Generic;
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Security.Cryptography.Core;
using Template10.Mvvm;
using Template10.Services.NavigationService;
using Windows.UI.Xaml.Navigation;
namespace UserControlTest.ViewModels
{
public class MainPageViewModel : ViewModelBase
{
private string _textToShow = "Initial text";
public string TextToShow
{
get { return _textToShow; }
set { Set(ref _textToShow, value); }
}
DelegateCommand _changeText;
public DelegateCommand ChangeText
=> _changeText ?? (_changeText = new DelegateCommand(ExecuteChangeTest, CanChangeText));
private void ExecuteChangeTest()
{
TextToShow = "Changed text";
}
private bool CanChangeText()
{
return true;
}
}
}
ShowText.xaml
<UserControl
x:Class="UserControlTest.Views.ShowText"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UserControlTest.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:UserControlTest.ViewModels" mc:Ignorable="d">
<UserControl.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</UserControl.DataContext>
<Grid>
<TextBlock x:Name="UserControlTextBlock"
Text="{Binding TextToShow}" />
</Grid>
</UserControl>

At first glance the problem is that your UserControl and your MainPage are using two different instances of ViewModel. When you create your static resource
<vm:MainPageViewModel x:Name="ViewModel" />
You're creating an instance of MainPageViewModel. This means that when you set the value in from your MainPage instance of MainPageViewModel, it's not propagating to the second instance of MainPageViewModel that your UserControl created.
No worries though, we can fix this.
The DataContext of your user control should be set automatically to its parent's DataContext.
So Let's assume for a moment that you use your UserControl in your MainPage.xaml
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<MyUserControls:MyUserControl />
In this instance, MyUsercontrol is using the MainPageViewModel as it's DataContext. HOWEVER, this probably won't work, it's not a finished solution.
What you need to do is go to your UserControl's Xaml.CS and create a dependency property that you can bind to.
public class MyUserControl : Control{
public string MyControlsText
{
get { return (string)GetValue(MyControlsTextProperty); }
set { SetValue(MyControlsTextProperty, value); }
}
public static readonly DependencyProperty MyControlsTextProperty =
DependencyProperty.Register("MyControlsText", typeof(string),
typeof(MyUserControl), new PropertyMetadata(String.Empty));
}
Now that we have our dependency property, in our UserControl's Xaml we can bind to it.
<Grid>
<TextBlock x:Name="UserControlTextBlock"
Text="{Binding MyControlsText}" />
</Grid>
And finally in our MainPage.Xaml we can finalize the binding
<MyUserControls:MyUserControl MyControlsText="{Binding TextToShow}" />
So with the above code here is what we are accomplishing:
The DataContext is set in the MainPage.xaml and all of the children of MainPage.xaml share this DataContext
We created a dependency property in our UserControl that we can bind to
We bind the XAML of our UserControl to our dependency property
We Bind our view model's text property to our new user controls dependency property.

Related

C#: How to populate combo items in UserControl

The following code works by having the combobox populated by the C# code behind at run-time.
I would like to populate the user control combos declaratively from XAML, similar to how the description label is populated.
This code is just for my personal use, so I won't be using complex MVVM models. I'd ideally like a solution that passes string arrays from the main XAMLcode, to the user control as I'd like to know how to do that.
Thanks in advance :-)
//Main Window.xaml
<Window
x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="Car Details"
SizeToContent="WidthAndHeight">
<StackPanel>
<local:myControl
x:Name="myMake"
myDescription="Make" />
<local:myControl
x:Name="myModel"
myDescription="Model" />
<local:myControl
x:Name="myYear"
myDescription="Year" />
</StackPanel>
</Window>
//MainWindow.xaml.cs
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//myMake is the name of a specific myControl
//myOption is the name of the combo within myControl
myMake.myOptions.ItemsSource = new string[] { "Ford", "Toyota" };
}
}
}
//myControl.xaml
<UserControl
x:Class="WpfApp1.myControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d">
<StackPanel>
<Label
Content="{Binding myDescription,FallbackValue=description}"
/>
<ComboBox
x:Name="myOptions"
Width="120" />
</StackPanel>
</UserControl>
//myControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public partial class myControl : UserControl
{
public myControl()
{
InitializeComponent();
this.DataContext = this;
}
public string myDescription
{
get { return (string)GetValue(myDescriptionProperty); }
set { SetValue(myDescriptionProperty, value); }
}
public static readonly DependencyProperty myDescriptionProperty = DependencyProperty.Register("myDescription", typeof(string), typeof(myControl), new PropertyMetadata(null));
}
}
You can declare an array of string in xaml like this:
<x:Array xmlns:s="clr-namespace:System;assembly=mscorlib" x:Key="myStringArray" Type="{x:Type s:String}">
<s:String>Ford</s:String>
<s:String>Toyota</s:String>
</x:Array>
Source: this answer
So your view becomes:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="Car Details" SizeToContent="WidthAndHeight">
<Window.Resources>
<!--Declaration of an array of string which is added to the ressources of the window-->
<x:Array xmlns:s="clr-namespace:System;assembly=mscorlib" x:Key="myStringArray" Type="{x:Type s:String}">
<s:String>Ford</s:String>
<s:String>Toyota</s:String>
</x:Array>
</Window.Resources>
<StackPanel>
<!--We get the array from the ressource by calling "StaticResource" with the key of the element to obtain-->
<local:myControl
x:Name="myMake" myDescription="Make" ArrayItemsSource="{StaticResource myStringArray}" />
<!--Do the same for the other usercontrol -->
<local:myControl
x:Name="myModel"
myDescription="Model" />
<local:myControl
x:Name="myYear"
myDescription="Year" />
</StackPanel>
In your usercontrol, you should not use this.DataContext = this; as this is bad practice since it prevents your usercontrol from inheriting the datacontext of the view (I know you are not planning on using MVVM but I think this should still be mentioned for other readers).
So because the datacontext is not the control, the bindings in the xaml of the usercontrol have to be modified like this: {Binding ElementName=myControlName, Path=theNameOfThePropertyIwantToBind}
I created a new dependency property to pass the array of string from the view so the usercontrol becomes:
Xaml:
<UserControl x:Class="WpfApp1.myControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1" x:Name="myControlName"
mc:Ignorable="d">
<StackPanel>
<Label
Content="{Binding ElementName=myControlName, Path=myDescription,FallbackValue=description}"
/>
<ComboBox
x:Name="myOptions" ItemsSource="{Binding ElementName=myControlName, Path=ArrayItemsSource}"
Width="120" />
</StackPanel>
The code behind:
public partial class myControl : UserControl
{
public myControl()
{
InitializeComponent();
//Bad practice
//this.DataContext = this;
}
public string myDescription
{
get { return (string)GetValue(myDescriptionProperty); }
set { SetValue(myDescriptionProperty, value); }
}
public string[] ArrayItemsSource
{
get { return (string[])GetValue(ArrayItemsSourceProperty); }
set { SetValue(ArrayItemsSourceProperty, value); }
}
public static readonly DependencyProperty myDescriptionProperty = DependencyProperty.Register("myDescription", typeof(string), typeof(myControl), new PropertyMetadata(null));
public static readonly DependencyProperty ArrayItemsSourceProperty = DependencyProperty.Register(nameof(ArrayItemsSource), typeof(string[]), typeof(myControl), new PropertyMetadata(null));
}

Mvvm Light, UWP and code behind

Base on this excellent presentation from Laurent Bugnion at Xamarin Evolve 2014, I'm trying to create my first UWP/MVVM Light application.
I created a very simple Article : ObservableObject class with 2 string properties : Référence and Désignation.
In the view model associated to the article list view, I have an action to create a new article :
public ArticlesViewModel(IArticleService dataService, INavigationService navigationService)
{
ArticleService = dataService;
NavigationService = navigationService;
CréeArticleCommand = new RelayCommand(CréeArticle);
}
public RelayCommand CréeArticleCommand { get; private set; }
private void CréeArticle()
{
if (!CréeArticleCommand.CanExecute(null))
return;
NavigationService.NavigateTo(ViewModelLocator.ArticleDetail_Key,
new ArticleViewModel(new Article(),
ArticleService,
NavigationService));
}
here is the XAML for my Article detail view :
<!-- language: xaml -->
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UniversalTest1.UWP.Articles"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Editors="using:DevExpress.UI.Xaml.Editors"
x:Class="UniversalTest1.UWP.Articles.Article_Detail"
mc:Ignorable="d"
xmlns:vm="clr-namespace:UniversalTest1.Data.ViewModels.Articles;assembly=UniversalTest1.Data"
d:DataContext="{d:DesignInstance Type=vm:ArticleViewModel, IsDesignTimeCreatable=True}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Référence :" HorizontalAlignment="Left" Margin="24,15,0,0" VerticalAlignment="Top"/>
<TextBlock Text="Désignation :" HorizontalAlignment="Left" Margin="10,52,0,0" VerticalAlignment="Top"/>
<Editors:TextEdit Text="{Binding Article.Référence, Mode=TwoWay}" HorizontalAlignment="Left" Margin="100,8,0,0" VerticalAlignment="Top" Width="300"/>
<Editors:TextEdit Text="{Binding Article.Désignation, Mode=TwoWay}" HorizontalAlignment="Left" Margin="100,45,0,0" VerticalAlignment="Top" Width="500"/>
<Button Content="Sauver" Command="{Binding SauverCommand}" HorizontalAlignment="Left" Margin="102,84,0,0" VerticalAlignment="Top"/>
</Grid>
</Page>
My problem here is that I have to define the DataContext in the code behind of my page :
public sealed partial class Article_Detail : Page
{
public Article_Detail()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
DataContext = (ArticleViewModel)e.Parameter;
}
}
Is there a way to keep the design time DataContext as defined in the d:DataContext part of the Xaml's Page, and at runtime, get the DataContext from the Navigation parameter ?
My goal here is to have the less amount possible of code in the code behind. So I would like to define the runtime DataContext in the XAML also.
You can make use of dependency injection to create design or runtime service instances for your viewmodel. Using a view model locator you can do something like this:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
if (!SimpleIoc.Default.IsRegistered<IArticleService>())
{
SimpleIoc.Default.Register<IArticleService, DesignArticleService>();
}
}
else
{
if (!SimpleIoc.Default.IsRegistered<IArticleService>())
{
SimpleIoc.Default.Register<IArticleService, ArticleService>();
}
}
SimpleIoc.Default.Register<ArticleViewModel>();
}
public ArticleViewModel ArticleViewModel => ServiceLocator.Current.GetInstance<ArticleViewModel>();
}
And in your App.xaml you register the locator
<Application
x:Class="UniversalTest1.App" // your namespace
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModel="using:UniversalTest1.Data.ViewModels"> // your namespace
<Application.Resources>
<ResourceDictionary>
<viewModel:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</ResourceDictionary>
</Application.Resources>
</Application>
And then you can reference it in your xaml like this:
<Page
...
DataContext="{Binding ArticleViewModel, Source={StaticResource Locator}}">
You could also take a look at the sample code here https://mvvmlight.codeplex.com/SourceControl/latest#Samples/Flowers/Flowers.Data/ViewModel/ViewModelLocator.cs
For this, you need to use your own implementation of NavigationService. The concept is to navigate to your page and call your ViewModel at the same time to handle parameters and set the DataContext.
Here are two samples of this pattern:
Prism: https://github.com/PrismLibrary/Prism/blob/master/Source/Windows10/Prism.Windows/Navigation/FrameNavigationService.cs
Template10: https://github.com/Windows-XAML/Template10/blob/master/Template10%20(Library)/Services/NavigationService/NavigationService.cs

WPF binding UserControl to MainWindow as parent is failed

I am newbie in XAML Databinding and I am stuck in this situation. I am using Mahapps MetroWindow.
Suppose that I have a UserControl named usrctrl_Camera_Control. I have a simple button there. The C# code is given below.
namespace TA141501005
{
public partial class usrctrl_Camera_Control : UserControl
{
public usrctrl_Camera_Control()
{
this.DataContext = this;
InitializeComponent();
}
}
The XAML is given below
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls" xmlns:local="clr-namespace:TA141501005" x:Class="TA141501005.usrctrl_Camera_Control"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366" Background="#FF2B2B2B" Height="738" Width="1336">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button x:Name="btn_Test" Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="472,59,0,0" VerticalAlignment="Top" Width="75" Grid.RowSpan="2" IsEnabled="{Binding Path=IsNyetEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
</Grid>
The C# code for MainWindow is given below.
namespace TA141501005
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : MetroWindow
{
usrctrl_Camera_Control usrctrl_camera_control;
public bool IsNyetEnabled { get; set; }
public MainWindow()
{
IsNyetEnabled = false;
this.DataContext = this;
InitializeComponent();
usrctrl_camera_control = new usrctrl_Camera_Control();
}
}
}
and the XAML code for MainWindow is given below.
<Controls:MetroWindow x:Class="TA141501005.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="Macromium System Control V1.0ES - TA141501005 [Engineering Sample]" Height="768" Width="1366" Background="#FF2B2B2B" ScrollViewer.VerticalScrollBarVisibility="Disabled" ResizeMode="NoResize" WindowStyle="ThreeDBorderWindow" WindowStartupLocation="CenterScreen" IsMinButtonEnabled="False" IsWindowDraggable="False" ShowMaxRestoreButton="False" ShowMinButton="False" ShowSystemMenuOnRightClick="False" IconOverlayBehavior="Flyouts">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button x:Name="btn_test" Content="Button" HorizontalAlignment="Left" Margin="589,590,0,0" VerticalAlignment="Top" Width="75" IsEnabled="{Binding IsNyetEnabled}"/>
</Grid>
I want to binding the property IsEnabled in btn_test in usrctrl_Camera_Control and btn_test in MainWindow into IsNyetEnabled in MainWindow. I set the IsNyetEnabled into false before I do InitializeComponent() in MainWindow.
The binding between btn_test.IsEnabled in MainWindow into IsNyetEnabled in MainWindow is done flawlessly. The btn_test in MainWindow is no longer enabled. (I know, I need to implement INotifyPropertyChanged to notify the subsriber if there is any change but for now, just leave it as is for simplicity).
But, the binding between btn_test.IsEnabled in usrctrl_Camera_Control into IsNyetEnabled in MainWindow is failed. I have used Visual Studio "Create Data Binding" wizard but it always return error when compiling.
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='TA141501005.MainWindow', AncestorLevel='1''. BindingExpression:Path=IsNyetEnabled; DataItem=null; target element is 'Button' (Name='btn_Test'); target property is 'IsEnabled' (type 'Boolean')
Do you have any suggestion? I have tried for whole day without a luck.
Is there any way to access parent datacontext without removing this.Datacontext = this?
Looking forward for your suggestion and explanation.
Thank you very much.
Edit.
I display my UserControl via Flyout.
Window parentWindow = Window.GetWindow(this);
object obj = parentWindow.FindName("mainFlyout");
Flyout flyout = (Flyout) obj;
flyout.Content = new SomeFlyOutUserControl();
flyout.IsOpen = !flyout.IsOpen;
Create the IsNyetEnabled property as a dependency property on the MainForm. This is the mechanism that will propagate changes in WPF
Example:
public static readonly DependencyProperty IsNyetEnabledProperty =
DependencyProperty.Register("IsNyetEnabled", typeof(bool),
typeof(MainWindow),new FrameworkPropertyMetadata(false));
public bool IsNyetEnabled
{
get { return (bool)GetValue(MainWindow.IsNyetEnabled); }
set { SetValue(MainWindow.IsNyetEnabled, value); }
}
To that you can bind your Button in the MainWindow directly.
For the UserControl though we have to add a shim, because the UserControl won't be able to find the ancestor when you create it.
Create on your UserControl like Moez posted another DependencyProperty:
public static readonly DependencyProperty IsButtonEnabledProperty =
DependencyProperty.Register("IsButtonEnabled", typeof(bool),
typeof(usrctrl_Camera_Control),new FrameworkPropertyMetadata(false));
public bool IsButtonEnabled
{
get { return (bool)GetValue(usrctrl_Camera_Control.IsButtonEnabledProperty); }
set { SetValue(usrctrl_Camera_Control.IsButtonEnabledProperty, value); }
}
Bind your UserControl button IsEnabled property to that.
Now as a last step we will have to connect the two Dependency Properties when you create your UserControl.
<local:usrctrl_Camera_Control x:Name="yourControl" ...Whatever else... IsButtonEnabled="{Binding Path=IsNyetEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}} />
This should work now.
I suggest you use DependencyProperty :
public static readonly DependencyProperty IsButtonEnabledProperty = DependencyProperty.Register(
"IsButtonEnabled", typeof(bool), typeof(UserControl1), new PropertyMetadata(default(bool)));
public bool IsButtonEnabled
{
get { return (bool)GetValue(IsButtonEnabledProperty); }
set { SetValue(IsButtonEnabledProperty, value); }
}
// Here Rename your UserControl To Test
<Grid>
<Button x:Name="btn_Test" Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="472,59,0,0" VerticalAlignment="Top" Width="75" Grid.RowSpan="2" IsEnabled="{Binding Path=IsButtonEnabled, ElementName=Test}"}" />
</Grid>
As #Frank J suggested, I modify his last step.
I create the usercontrol during runtime, not from the XAML. Therefore it would be look like this for the last step.
usrctrl_camera_control = new usrctrl_Camera_Control();
Binding b = new Binding("IsNyetEnabled");
b.Source = this;
b.Mode = BindingMode.OneWay;
usrctrl_camera_control.SetBinding(usrctrl_Camera_Control.IsButtonEnabledProperty, b);
Thanks all.. I hope it would be useful for those who have the same problem with me.

How to bind a property from my usercontrol content control to a property?

I have a UserControl like this:
<UserControl x:Class="MySample.customtextbox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="300">
<Grid>
<TextBox x:Name="Ytextbox" Background="Yellow"/>
</Grid>
</UserControl>
I want use my control in mvvm pattern ...i want that i can bind a property in my viewmodel to Ytextbox Text Property
<CT:customtextbox ?(Ytextbox)Text ="{binding mypropertyinviewmodel}"/>
...how can I do it?
You should create a property on the UserControl and bind that internally to the TextBox's text.
i.e.
<UserControl Name="control" ...>
<!-- ... -->
<TextBox Text="{Binding Text, ElementName=control}"
Background="Yellow"/>
public class customtextbox : UserControl
{
public static readonly DependencyProperty TextProperty =
TextBox.TextProperty.AddOwner(typeof(customtextbox));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Usage:
<CT:customtextbox Text="{Binding mypropertyinviewmodel}"/>
(Do not set the DataContext in the UserControl to itself unless you want all external bindings which expect the DataContext to be inherited to fail, use ElementName or RelativeSource for internal bindings)

Setting Command Target in XAML

I am having a hard time understanding the CommandTarget property for a RoutedCommand.
Basically, I have some static commands that have implementations in a user control (not the window). I create a commandbinding in the user control. If I declare the button in the usercontrol, then I am able to use my routed event. However, when the button is outside of the usercontrol, then I cannot use my routed event. I think the command target will solve my issue.
So how do I set the commandtarget for the toolbar usercontrol's button, so that the Container's Executed and CanExecuted is called?
Edited Code with changes from micahtan changes, but I still can't get it to CanExecute or Execute.
Window XAML:
<Window x:Class="RoutedCommands.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RoutedCommands"
xmlns:toolbar="clr-namespace:RoutedCommands.Toolbar"
Title="Window1" Height="300" Width="300">
<StackPanel>
<local:Container Width="100" Height="25" x:Name="MyContainer" />
<toolbar:Toolbar Width="100" Height="25" CommandTarget="{Binding MyContainer}" />
</StackPanel>
</Window>
Toolbar XAML:
<UserControl x:Class="RoutedCommands.Toolbar.Toolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RoutedCommands"
x:Name="MyToolbar"
Height="300" Width="300">
<Grid>
<Button Command="{x:Static local:Commands.MyCommand}" Content="Try Me" CommandTarget="{Binding ElementName=MyToolbar, Path=CommandTarget, Mode=OneWay}" />
</Grid>
</UserControl>
Toolbar CS:
public partial class Toolbar : UserControl
{
public Toolbar()
{
InitializeComponent();
}
// Using a DependencyProperty as the backing store for CommandTarget. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(Toolbar), new UIPropertyMetadata(null));
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
}
Container XAML:
<UserControl x:Class="RoutedCommands.Container"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RoutedCommands"
Height="300" Width="300">
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.MyCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
</UserControl.CommandBindings>
<Grid>
<Button Command="{x:Static local:Commands.MyCommand}" Content="Click Me" />
</Grid>
</UserControl>
Container CS:
public partial class Container : UserControl
{
public Container()
{
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
Console.WriteLine("My Command Executed");
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
Console.WriteLine("My Command Can Execute");
e.CanExecute = true;
}
}
RoutedCommands:
namespace RoutedCommands
{
public static class Commands
{
public static readonly RoutedUICommand MyCommand = new RoutedUICommand();
}
}
If you want to use CommandTargets, I would create a CommandTarget DependencyProperty on your custom UserControl, similar to the way it's defined on ButtonBase.
After doing that, set your Button's CommandTarget to your custom UserControl's CommandTarget.
EDIT: Code Sample
Rudi's comments are valid if you're doing an MVVM architecture -- RelayCommands or some other form of wrapped delegates work well in that case. Based on your code sample, it didn't look like you were using that approach, hence my original comment.
As for the code, you only need to change your ToolBar class. This assumes your MyCommand class inherits from RoutedUICommand. Here's the XAML:
<UserControl
x:Class="WPFCommandTarget.CustomToolBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFCommandTarget"
x:Name="theControl">
<Grid>
<Button
x:Name="theButton"
Command="{x:Static local:Commands.MyCommand}"
CommandTarget="{Binding ElementName=theControl, Path=CommandTarget, Mode=OneWay}"
Content="Try Me" />
</Grid>
</UserControl>
And here's the code-behind:
using System.Windows;
using System.Windows.Controls;
namespace WPFCommandTarget
{
/// <summary>
/// Interaction logic for CustomToolBar.xaml
/// </summary>
public partial class CustomToolBar : UserControl
{
public CustomToolBar()
{
InitializeComponent();
}
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandTarget. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CustomToolBar), new UIPropertyMetadata(null));
}
}
Please note that I've changed some of the class names/namespaces in my test project. You'll have to change them to suit your needs.
Have you concidered to rather use the RelayCommand or DelegateCommand! Thy might be more suited to what you need?
For a example of using RelayCommand, read this article by Josh
Brian Noyes also have a excellent article available here

Categories