Can someone tell me what am I doing wrong? I have already tried everything, the pirmers that I downloaded from the Internet work, I made a minimal example, but it does not work.
I can't connect mine ViewModel in View
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:TestViewModel}">
<Label Content="{Binding Wtf}"/>
</DataTemplate>
</Grid.Resources>
</Grid>
public class TestViewModel
{
public string Wtf => "wtf???";
public TestViewModel() {}
}
I'm trying to connect the view model like this, so that I can use dependency injection later. But my Binding "wtf" does not display
The two standard ways of assigning the ViewModel to the View are
1] In the Xaml - this only works if your ViewModel has a paramaterless constructor.
<Window ... >
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
...
</Window>
2] In the code behind constructor of the View - you can use an IoC container for injected services to the ViewModel.
public MainView()
{
DataContext = new MainViewModel();
InitializeComponent();
}
or
public MainView()
{
DataContext = IoCContainer.GetInstance<MainViewModel>();
InitializeComponent();
}
For more details, including a more advanced way to assign the ViewModel that will provide data at design time, check out my blog post.
The code provided is not showing the whole thing.
There are 2 missing parts :
In the code behind instantiate the "TestViewModel" and put it in the DataContext.
Introduce a "ContentControl" that its DataContext was created as mentioned above.
The DataTemplate is just a declaration and not making the presentation.
The technique you are attempting to use is somehow advanced. It tells WPF that when a given class is encountered by a ContentControl , the Data Template is being used.
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:TestViewModel}">
<Label Content="{Binding Wtf}"/>
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding }"/>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
Related
Is it not possible to have multiple layers of UserControls containing ContentControl?
I am trying to create Views for different Models that are derived, so I'd like to eliminate the need to re-create the Views for each object type, and instead provide a ContentControl, or a ContentPresenter to inject the "rest of the view". However, I can only go one level deep with this method.
Here's a simplified example.(I've removed some of the xmlns). In my case, I'm working with significantly more complex Views, and trying to eliminate duplicate code in multiple places, concerned for changes later.
I have a Base UserControl, we'll call it UserControlLevel1
<UserControl x:Class="ContentControlNesting.UserControlLevel1"
x:Name="userControlLevel1"
xmlns:local="clr-namespace:ContentControlNesting">
<StackPanel>
<TextBlock Text="UserControlLevel1ContentTop"/>
<ContentControl Content="{Binding ElementName=userControlLevel1, Path=ChildContent}"/>
<TextBlock Text="UserControlLevel2ContentBottom"/>
</StackPanel>
</UserControl>
It has the following DependencyProperty on the UserControl
namespace ContentControlNesting
{
public partial class UserControlLevel1 : UserControl
{
public UserControlLevel1()
{
InitializeComponent();
}
public static readonly DependencyProperty ChildContentProperty = DependencyProperty.Register("ChildContent", typeof(UIElement), typeof(UserControlLevel1), new PropertyMetadata(null));
public UIElement ChildContent
{
get { return (UIElement)GetValue(ChildContentProperty); }
set { SetValue(ChildContentProperty, value); }
}
}
}
The ContentControl will be used in the following UserControl called UserControlLevel2. This UserControl works fine, just the way I would expect. Or rather UserControlLevel1 works properly within UserControlLevel2.
<UserControl x:Class="ContentControlNesting.UserControlLevel2"
x:Name="userControlLevel2"
xmlns:local="clr-namespace:ContentControlNesting">
<local:UserControlLevel1>
<local:UserControlLevel1.ChildContent>
<StackPanel>
<TextBlock Text="UserControlLevel2ContentTop"/>
<ContentControl Content="{Binding ElementName=userControlLevel2, Path=ChildContent}"/>
<TextBlock Text="UserControlLevel2ContentBottom"/>
</StackPanel>
</local:UserControlLevel1.ChildContent>
</local:UserControlLevel1>
</UserControl>
Likewise, it has a single DependencyProperty for the ContentControl on this UserControl like the first. I've also tried this with differently named DependencyProperties.
namespace ContentControlNesting
{
public partial class UserControlLevel1 : UserControl
{
public UserControlLevel1()
{
InitializeComponent();
}
public static readonly DependencyProperty ChildContentProperty = DependencyProperty.Register("ChildContent", typeof(UIElement), typeof(UserControlLevel1), new PropertyMetadata(null));
public UIElement ChildContent
{
get { return (UIElement)GetValue(ChildContentProperty); }
set { SetValue(ChildContentProperty, value); }
}
}
}
Okay, so at this point, everything seems to be working fine. I've added additional content inside of the ContentControl of UserControlLevel1, and I've added another ContentControl within my UserControlLevel2 UserControl.
The problem is when I try to introduce a 3rd Tier of either UserControl or my MainWindow. Anything I add to the ContentControl of UserControlLevel2 just does not appear.
<Window x:Class="ContentControlNesting.MainWindow"
xmlns:local="clr-namespace:ContentControlNesting"
Title="MainWindow" Height="200" Width="300">
<local:UserControlLevel2>
<local:UserControlLevel2.ChildContent>
<StackPanel>
<TextBlock Text="Main Window Content Text"/>
</StackPanel>
</local:UserControlLevel2.ChildContent>
</local:UserControlLevel2>
</Window>
Am I trying to do something that's not possible? Or am I doing something wrong with ContentControl and the DependencyProperties? Should I be looking at this with a different approach?
It is possible. The system cannot resolve the ElementName in the Binding. The solution is to use the relative binding. Just replace the following line in UserControlLevel2 and your are done:
<ContentControl Content="{Binding Path=ChildContent, RelativeSource={RelativeSource AncestorType={x:Type local:UserControlLevel2}}}"/>
I'm totally lost with dependancy objects and binding. I often get things working without understanding why and how, this question is about knowing what should be happening.
I have a tiny user control with the following XAML
<Grid>
<Image Source="{Binding Icon}"></Image>
<TextBlock Text="{Binding Title}"></TextBlock>
</Grid>
My code behind has the following
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(Image), typeof(MenuItem));
public Image Icon
{
get { return (Image)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(String), typeof(MenuItem));
public string Title
{
get { return (string)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
My MainWindow is empty, other than a reference to this control and to the ResourceDictionary. In the MainWindow code behind, I set the DataContext in the constructor.
<Window x:Class="AppUi.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:AppUi.Control"
Title="">
//set up to Resource Dictionary - all binding and styling works fine :)
<loc:MenuItem Icon="{Binding MailIcon}" Title="{Binding MailTitle}"></loc:MenuItem>
In the ModelView for the MainWindow, I have the following 2 properties
private Image_mailIcon;
public Image MailIcon{
//inotifyproperty implementation
}
private string _mailTitle;
public string MailTitle{
//inotifyproperty implementation
}
My question is, in the UserControl, how do I do the binding? Since it's a user control within a MainWindow, and the MainWindow already has a datacontext, I think the UserControl will inherit the DataContext from the parent (From what I have read).
So, in my UserControl XAML, should I be binding to the MainWindow's Code Behind properties OR to the ViewModel properties?
In other words, should my UserControl be
<Grid>
<Image Source="{Binding MailIcon}"></Image>
<TextBlock Text="{Binding MailTitle}"></TextBlock>
</Grid>
OR
<Grid>
<Image Source="{Binding Icon}"></Image>
<TextBlock Text="{Binding Title}"></TextBlock>
</Grid>
Or, because I'm using a DataContext and the UserControl inherits, do I even need the Dependancy Properties at all?
You normally don't want to overwrite DataContext passed through visual tree so you can use either ElementName or RelativeSource binding inside UserControl to change binding context. The easiest way to achive this is give UserControl some name and use it ElementName binding
<UserControl ... x:Name="myUserControl">
<!-- ... -->
<Grid>
<Image Source="{Binding Icon, ElementName=myUserControl}"/>
<TextBlock Text="{Binding Title, ElementName=myUserControl}"/>
</Grid>
<!-- ... -->
</UserControl>
This way binding is DataContext independent. You can also create UserControl with assumption it will always work with only specific type of DataContext and then you just use Path from that view model type but then DataContext of that UserControl must always be of the view model it's designed for (mostly inherited through visual tree)
<UserControl ...>
<!-- ... -->
<Grid>
<Image Source="{Binding MailIcon}"/>
<TextBlock Text="{Binding MailTitle}"/>
</Grid>
<!-- ... -->
</UserControl>
I would also change type of Icon property from Image to ImageSource for example. You already have Image control inside your UserControl and you just want to bind its Source
in the UserControl, how do I do the binding? ... the UserControl will inherit the DataContext from the parent
That is correct, the UserControl will inherit the DataContext from the parent Window. Therefore you can data bind from the UserControl directly to the parent Window.DataContext. Please note that you would bind to whatever object has been set as the DataContext, regardless of whether that was the code behind or a separate view model class.
However, you don't have to data bind to the parent's DataContext object in this situation... you have other options. You could data bind to your own UserControl DependencyPropertys using a RelativeSource Binding like this:
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:YourUserControl}}}" />
You could also name your UserControl and reference its properties like this:
<TextBlock Text="{Binding Title, ElementName=YourUserControlName}" />
While this example seems to be more concise, don't overlook the first example, as RelativeSource is a useful and powerful friend to have.
should I be binding to the MainWindow's Code Behind properties OR to the ViewModel properties?
That's your choice... what do you want or need to data bind to? you just need to know that a direct data binding will use the auto set DataContext value, so if you don't want to use that, then you can just specify a different data source for the Binding as shown above.
Finally, regarding the need to use DependencyPropertys... you only need to declare them if you are developing a UserControl that needs to provide data binding abilities.
I'm building a custom UserControl in WPF, which has a ViewModel associated. I also want do dynamically make controls in the code behind. But now I'm having problems binding the generated controls with the ViewModel properties. My code is:
<UserControl x:Class="SVT.Teste.UserControl1"
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="300" d:DesignWidth="300"
DataContext="UserControl1ViewModel">
<Grid Name="GridContainer">
</Grid>
</UserControl>
and code behind:
public UserControl1()
{
InitializeComponent();
System.Windows.Controls.Button newBtn = new Button();
newBtn.SetBinding(Button.ContentProperty, new Binding("Test"));
GridContainer.Children.Add(newBtn);
}
public class UserControl1ViewModel
{
private string test = "ola";
public string Test
{
get { return test; }
}
}
When I run this I get:
"System.Windows.Data Error: 40 : BindingExpression path error: 'Test'
property not found on 'object' ''String' (HashCode=-946585093)'.
BindingExpression:Path=Test; DataItem='String' (HashCode=-946585093);
target element is 'Button' (Name=''); target property is 'Content'
(type 'Object')"
Can you help me?
You are setting DataContext property of UserControl1 to a string instead of your view model instance.
You need to do something like this:
<UserControl xmlns:local="clr-namespace:NAMESPACE_WHERE_VIEWMODEL_IS_DEFINED">
<UserControl.DataContext>
<local:UserControl1ViewModel />
</UserControl.DataContext>
<!-- unrelated code omitted -->
</UserControl>
You are setting you DataContext to the type, not an instance that has the properties.
In your method that creates the user control do :
public UserControl1()
{
InitializeComponent();
System.Windows.Controls.Button newBtn = new Button();
newBtn.SetBinding(Button.ContentProperty, new Binding("Test"));
GridContainer.Children.Add(newBtn);
**DataContext = new UserControl1ViewModel();**
}
You still have more work to do. The way you have it no notifications or update will happen. Implement the INotifyPropertyChanged interface (on UserControlViewModel). And remove setting DataContext in the XAML to the type.
try with this binding
Binding MyBinding = new Binding();
MyBinding.Path = new PropertyPath("Test");
newBtn.DataContext = new UserControl1ViewModel(); //or MyBinding.Source = new //UserControl1ViewModel();
newBtn.SetBinding(Button.ContentProperty, MyBinding);
max is right, but i have another question. why do you want create your usercontrol dynamic when you have a viemwodel you wanna bind to? makes no sense to me. let me explain:
if you have a viewmodel - you know in mind how this viewmodel should be rendered and what the bindings are. so you could create a usercontrol/view for this viewmodel
MyUserControl1View.xaml
<UserControl>
<Grid>
<Button Content="{Binding Test}"/>
<!-- more controls and binding if the viewmodel expose more-->
</Grid>
</UserControl>
so what you have now is a representation of your viewmodel. they are not connnected but your viewmodel should look like this and the binding are set. till now no datacontext is set at all.
all you have to do now is to go the viewmodel first approach and the use of datatemplates.
let us assume the following in your mainwindow
<Window>
<Window.Resources>
<DataTemplate Datatype="{x:Type local:Usercontrol1viewmodel}">
<view:MyUserControl1View/>
</DataTemplate>
</Window.Resources>
now wpf knows how to render Usercontrol1viewmodel.
one step more in your mainwindow viewmodel you handle your Usercontrol1viewmodel.
public Usercontrol1viewmodel MyWhatEver {get;set;}
if you bind this property to a contentpresenter, you will see the wpf magic;)
<ContentPresenter Content="{Binding MyWhatEver}"/>
now you see the MyUserControl1View in the contentpresenter, no dynamic view code needed. just go with your viewmodels.
ps: feel free to edit my bad english.
I am very new to WPF and testing some things that I would like to include in an application that I will be working on. I have a 2 row ListView (bound to a textbox) with the names Scott Guthrie and Jon Skeet in it. I am trying to select "Scott Guthrie" in the ListView and have it populate the TextBox. I want to be able to edit the text and tab off and have the ListView updated.
Edit:I removed the code since that really didn't add anything to the question.
Wow, that's really complicated what you've got there.
This can be accomplished in a very simple way. You need a model to represent the programmer, a view model to hold a list of programmers, and simple binding to take care of the rest.
The model:
public sealed class Programmer
{
public string Name { get; set; }
}
Its very simple. An object representing a programmer with a name. We must encapsulate the name within an object because strings are immutable in .NET. If you tried binding against a single string in a list of strings, changes wouldn't propagate.
The collection of programmers is kept in a ViewModel. In this case, I call it ViewModel, because I have no imagination. This view model contains everything that the view binds against. In this case, its the list of programmers.
public sealed class ViewModel
{
public ObservableCollection<Programmer> Programmers { get; private set; }
public ViewModel()
{
Programmers = new ObservableCollection<Programmer>();
}
}
The ViewModel is set as the DataContext of our view. The DataContext flows down the visual tree, and we can bind against it at any point.
public MainWindow()
{
var vm = new ViewModel();
vm.Programmers.Add(new Programmer { Name = "Jon Skeet" });
vm.Programmers.Add(new Programmer { Name = "Scott Guthrie" });
DataContext = vm;
InitializeComponent();
}
You can set the DataContext in any way you want; I'm doing it here for simplicity's sake.
In the UI, I simply bind the ListView against the list of Programmers in the ViewModel (the DataContext, unless otherwise stated, is the root of the binding path). I then bind the TextBox against the SelectedItem of the ListBox. You select a Programmer from the list, which then becomes the SelectedItem, which I can then change the Name of.
<Window
x:Class="Programmers.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:t="clr-namespace:Programmers"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
x:Name="list"
ItemsSource="{Binding Programmers}"
DisplayMemberPath="Name" />
<TextBox
Grid.Column="1"
VerticalAlignment="Top"
Text="{Binding SelectedItem.Name, ElementName=list}" />
</Grid>
</Window>
Simple, once you get the hang of it.
This works (except that you need to validate the textbox since you can enter any text.. a dropdown might be a better choice).
View:
<TabItem x:Name="RightTabPage" Header="RightModel" DataContext="{Binding Right}">
<StackPanel>
<TextBox Text="{Binding SelectedGuru}"/>
<ListView SelectedItem="{Binding SelectedGuru}" ItemsSource="{Binding Gurus}"/>
</StackPanel>
</TabItem>
ViewModel:
public class RightViewModel
{
public RightViewModel()
{
Gurus = new[] {"Scott Guthrie", "Jon Skeet"};
SelectedGuru = Gurus.First();
}
public string SelectedGuru { get; set; }
public IEnumerable<string> Gurus{ get; set; }
}
I have a wpf user control, which exposes a single custom dependency property. Inside the user control, a textblock binds to the value of the dp. This databinding works in all scenarios except when the data source is an object.
The minimal code necessary to reproduce this is:
this is the main part of the user control
<StackPanel Orientation="Horizontal">
<TextBlock Text="**SimpleUC** UCValue: "/>
<TextBlock Text="{Binding UCValue}"/>
</StackPanel>
and the user control code behind:
public SimpleUC()
{
InitializeComponent();
this.DataContext = this;
}
public string UCValue
{
get { return (string)GetValue(UCValueProperty); }
set { SetValue(UCValueProperty, value); }
}
public static readonly DependencyProperty UCValueProperty =
DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));
this is the test window. I imported my project xml namespace as "custom"
<Window.Resources>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="20"/>
</Style>
</Window.Resources>
<StackPanel>
<StackPanel>
<TextBlock Text="This fails to bind:"/>
<custom:SimpleUC UCValue="{Binding SomeData}"/>
</StackPanel>
<StackPanel>
<TextBlock>The same binding on a regular control like Label</TextBlock>
<Label Content="{Binding SomeData}"/>
</StackPanel>
<Slider x:Name="sld" />
<StackPanel>
<TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
<custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
</StackPanel>
</StackPanel>
and the test window code behind is:
public TestWindow()
{
InitializeComponent();
this.DataContext = this;
}
//property to bind to
public string SomeData { get { return "Hello S.O."; } }
When I turn on the diagnostic tracing on the TestWindow, it spits out the error "BindingExpression path error:
'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
The binding expression is the same as the one I used in the neighboring label and it worked fine. This behavior seems really bizarre to me. Can anyone shed some light?
You set DataContext of your SimpleUC to itself here
public SimpleUC()
{
InitializeComponent();
this.DataContext = this; // wrong way!
}
so when you use binding here
<custom:SimpleUC UCValue="{Binding SomeData}"/>
it searches property SomeData in control's data context which is set to this object because code in SimpleUC constructor overrides value of DataContext and it is not set to TestWindow object anymore as you expected. That's why your solution works - it doesn't affect DataContext which is inherited from window. Also you can keep this.DataContext = this; but set element where to search property explicitly like this (skipped irrelevant)
<Window ... Name="wnd1">
<custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
...
But my oppinion is that your variant from the answer looks more convenient to me, setting data context to this is not very good practice.
Hope it helps.
If you must use a UserControl, your
<TextBlock
Text="{Binding RelativeSource={RelativeSource Self},
Path=Parent.Parent.UCValue}"
/>
is an ok way to do it and
<TextBlock
Text="{Binding UCValue,
RelativeSource={RelativeSource FindAncestor,custom:SimpleUC,1}}"
/>
is better because you don't rely on the control hierarchy and possible instantiation order issues.
However I would recommend for this kind of situation that you use "custom controls" instead of "user controls". They take a little bit of getting used to, but they are much more powerful because their XAML is the template itself which means you can use TemplateBinding and {RelativeSource TemplatedParent}.
In any case, DataContext = this; is definitely to be avoided.