In my windows phone application, I made a user control that has some text blocks and images. It's something like a control to show posts like Facebook. I want to use this user control in a long list selector, but whenever I try to bind data to it I get no data. Please help me.
This is the MainPage.xaml
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector Name="myLLS">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<local:Posts TitleText={Binding TitleText}>
</local:Posts>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
And this is the code behind
public class TestData
{
private string _TitleText;
public string TitleText
{
get { return _TitleText; }
set { _TitleText = value; }
}
public TestData(string Text)
{
This.TitleText = Text;
}
}
And this is the UserControl xaml code
<UserControl x:Class="BindingUserControlTest.TestBind"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" Height="125.889" Width="227.974">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<TextBlock x:Name="lblTitle" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
<TextBlock x:Name="lblDescription" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Margin="0,32,0,0" Width="218" Height="84"/>
</Grid>
And this is the code behind :
private string _ShownTitle;
public string ShownTitle { get { return _ShownTitle; } set { _ShownTitle = value; }}
You need to use DependencyProperties to be able to bind to an attribute. Rather than re-write the code for you, I will give you a link to a blog by Jerry Nixon, who explains the process well.
http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html
EDIT:
Code Behind for the Usercontrol would look like.
public sealed partial class ExampleControl : UserControl
{
public static readonly DependencyProperty exampleProperty = DependencyProperty.Register("ExampleData", typeof(Double), typeof(NutritionLabelControl), null);
public ExampleControl()
{
InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
}
public Double ExampleData
{
get { return (Double)GetValue(exampleProperty); }
set
{
SetValue(exampleProperty, value);
}
}
}
Then in your userControls XAML you would have something like:
<UserControl>
<Grid x:Name="LayoutRoot">
<TextBlock Text="{Binding ExampleData}" />
</Grid>
</UserControl>
You can then use the same Binding format in the MainPage.xaml as in the usercontrols XAML.
Related
I'm trying to figure out how to bind a property from my MainWindowViewModel to a ContentControl that is based on another View.
RelativeSource Binding seems not to work since the View is in another xaml file?
I tried with dependancy property but I didn't understand how to do this correctly I guess.
What I want to achieve here is that when I type in the TextBox of the MainWindow that all 3 views (contentcontrols) also view the updated data. It should be a demo to illustrate that in MVVM the ViewModel can change without knowledge of the Views and different Views react to it.
Sadly RelativeSource Binding and DependancyProperty didn't work for me or I missed a point.
MainWindow.xaml
<Window x:Class="MVVMDemo.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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<TextBlock Text="MVVM Demo" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
<TextBox Text="{Binding TestString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="200" Background="Black" Foreground="White" Margin="0 20 0 0"/>
<Grid Margin="0 20 0 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<ContentControl Grid.Column="0" Grid.Row="0" Content="{Binding ViewOne}"/>
<ContentControl Grid.Column="1" Grid.Row="0" Content="{Binding ViewTwo}"/>
<ContentControl Grid.Column="2" Grid.Row="0" Content="{Binding ViewThree}"/>
</Grid>
</StackPanel>
</Window>
MainWindowViewModel
public class MainWindowViewModel : ViewModelBase
{
/// <summary>
/// String to change the reaction of views
/// </summary>
private string _TestString;
public string TestString
{
get { return _TestString; }
set { _TestString = value; NotifyPropertyChanged(); }
}
private object _ViewOne { get; set; }
public object ViewOne
{
get { return _ViewOne; }
set { _ViewOne = value; NotifyPropertyChanged(); }
}
private object _ViewTwo { get; set; }
public object ViewTwo
{
get { return _ViewTwo; }
set { _ViewTwo = value; NotifyPropertyChanged(); }
}
private object _ViewThree { get; set; }
public object ViewThree
{
get { return _ViewThree; }
set { _ViewThree = value; NotifyPropertyChanged(); }
}
public MainWindowViewModel()
{
ViewOne = new ViewOne();
ViewTwo = new ViewTwo();
ViewThree = new ViewThree();
TestString = "ABC";
}
}
ViewOneViewModel
<UserControl x:Class="MVVMDemo.Views.ViewOne"
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:MVVMDemo.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="White">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=TestString, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Foreground="Black"/>
<TextBlock Text="{Binding TestStringProperty}" Foreground="Black"/>
</StackPanel>
</Grid>
</UserControl>
ViewOneViewModel
public class ViewOneViewModel : ViewModelBase
{
// this doesn't help
public static readonly DependencyProperty TestStringProperty =
DependencyProperty.Register("TestString", typeof(string), typeof(MainWindowViewModel), new PropertyMetadata(null));
}
I believe your issue lies here:
<TextBlock Text="{Binding Path=TestString, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Foreground="Black"/>
Binding Path=TestString should instead be Binding Path=DataContext.TestString as the RelativeSource is looking at the window now, not the window's model.
I have following resourcedictionay.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:samplePrjkt"
>
<ToolBar x:Key="MyToolbar" Height="120">
<!--Template-->
<GroupBox Header="Template" Style="{StaticResource ToolbarGroup}" Margin="3">
<StackPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel Orientation="Vertical" Margin="0,2,0,2">
<TextBlock Text="{Binding TextValue}"></TextBlock>
</StackPanel>
</StackPanel>
</GroupBox>
</ToolBar>
</ResourceDictionary>
that resourcedictionay used in following WPF user-control like follows.
<UserControl x:Class="Sampleprjkt.sample.sampleWindow"
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:Sampleprjkt"
>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="29*"/>
<RowDefinition Height="107*"/>
</Grid.RowDefinitions>
<ContentControl Content="{StaticResource MyToolbar}"/>
</Grid>
</UserControl>
I'm trying to bind value to this text block inside the WPF user-control constructor like follows
public partial class SampleWindow : UserControl
{
private string _textValue;
public string TextValue
{
get { return _textValue; }
set
{
_textValue = value;
}
}
public SampleWindow()
{
InitializeComponent();
_textValue = "XXXXX";
}
}
but once I run this, I can see "XXXXX" value not set to <TextBlock Text="{Binding TextValue}"></TextBlock> , what I missed here ?
Your ContentControl is missing a DataContext, which is null. The Binding will always refer to the object in the DataContext and thus the Binding will not find the TextValue.
You could simply set the DataContext of the UserControl to itself:
public SampleWindow()
{
InitializeComponent();
_textValue = "XXXXX";
this.DataContext = this;
}
The DataContext is inherited down to the TextBlock, which will now display the text.
The path of a binding that you define in XAML ("TextValue" in your case) refers to a name of the property of the current DataContext of the element (TextBlock in your case) or the source of the binding.
This means that you should either set the DataContext as suggested by #Sharada Gururaj:
public SampleWindow()
{
InitializeComponent();
_textValue = "XXXXX";
DataContext = this;
}
...or specify an explicit source of the binding:
<TextBlock Text="{Binding Path=TextValue, Source={RelativeSource AncestorType=UserControl}}"></TextBlock>
I'm trying to create a DataTemplate for a View, to show a specific UserControl type (like a texbox, combobox, custom control or another View) based on the type of object it is bound to.
I have the following MVVM framework:
FieldView is tied to an instance of FieldPresenter, and should display a <Textblock /> for the "Label" property, and a UserControl or another View for the Value (based on the Type of the value), with it's DataSource set to the Value property of the Presenter. Currently, I do not have the second part working. I can't figure out how to write a WPF template for what I need.
ViewModel:
public class FieldPresenter : Observable<object>, IFieldPresenter, INotifyPropertyChanged
{
public FieldPresenter() { }
public FieldPresenter(object value)
{
Value = value;
}
object IFieldPresenter.Value
{
get
{
return base.Value;
}
set
{
base.Value = value;
OnPropertyChanged("Value");
}
}
private string _label;
public virtual string Label
{
get
{
return _label;
}
private set
{
_label = value;
OnPropertyChanged("Label");
}
}
}
View:
<UserControl x:Class="My.Views.FieldView"
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:ViewModels="clr-namespace:My.ViewModels"
mc:Ignorable="d"
d:DesignHeight="24" d:DesignWidth="100">
<UserControl.DataContext>
<ViewModels:FieldPresenter/>
</UserControl.DataContext>
<UserControl.Template>
<ControlTemplate>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
</Grid.ColumnDefinitions>
<StackPanel Margin="0,0,0,0" HorizontalAlignment="Stretch" Width="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth}">
<TextBlock Text="{Binding Label}" FontWeight="Bold" Height="32" HorizontalAlignment="Stretch"/>
<TextBox Text="{Binding Value}" Height="Auto" HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
I'm curious if what I'm trying to do is even possible, or if I can workaround it by making my Presenter viewmodel return a UserControl rather than an object value, and have the Presenter parse the UserControl Type from the object type, but I don't feel like my Presenter should be instantiating Controls (or what is technically an unbound view). Should I make an interface, something like IViewAs<controlType> { controlType View { get; } }?
How else would I replace <TextBox Text="{Binding Value}" /> in the above script with some kind of template of a UserControl based on the databound object's type?
You almost certainly want a ContentTemplateSelector :
Code:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Primitive primitive;
primitive = new Sphere();
// primitive = new Cube();
DataContext = primitive;
}
}
internal abstract class Primitive
{
public abstract string Description { get; }
}
internal class Cube : Primitive
{
public override string Description
{
get { return "Cube"; }
}
}
internal class Sphere : Primitive
{
public override string Description
{
get { return "Sphere"; }
}
}
public class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var frameworkElement = container as FrameworkElement;
if (frameworkElement != null && item != null)
{
if (item is Cube)
{
return frameworkElement.FindResource("CubeTemplate") as DataTemplate;
}
if (item is Sphere)
{
return frameworkElement.FindResource("SphereTemplate") as DataTemplate;
}
}
return base.SelectTemplate(item, container);
}
}
}
XAML:
<Window x:Class="WpfApplication1.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:local="clr-namespace:WpfApplication1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="Window"
Title="MainWindow"
Width="525"
Height="350"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<local:MyTemplateSelector x:Key="myTemplateSelector" />
<DataTemplate x:Key="CubeTemplate" DataType="local:Cube">
<Border BorderBrush="Blue"
BorderThickness="1"
CornerRadius="5" />
</DataTemplate>
<DataTemplate x:Key="SphereTemplate" DataType="local:Sphere">
<Border BorderBrush="Red"
BorderThickness="1"
CornerRadius="50" />
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="{Binding Description}"
d:DataContext="{d:DesignInstance local:Primitive}" />
<ContentControl Grid.Row="1"
Content="{Binding}"
ContentTemplateSelector="{StaticResource myTemplateSelector}" />
</Grid>
</Window>
Result:
See the documentation for more:
https://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector(v=vs.110).aspx
I created a user-control which is a button. When implementing the usercontrol into a parrent control, I'd like to set the icon and tooltip aswell as an enum property that indicates the buttons behaviour.
This is my Button.xaml
<UserControl x:Class="Messenger.Controls.MainWindow.Button"
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="30" d:DesignWidth="30">
<Grid>
<Button Name="btTabButton" Height="30" Width="30">
<Image x:Name="Icon" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button.ToolTip>
<ToolTip x:Name="Hover">
<TextBlock x:Name="HoverText"/>
</ToolTip>
</Button.ToolTip>
</Button>
</Grid>
And the Button.xaml.cs
namespace Messenger.Controls.MainWindow
{
public partial class Button : UserControl
{
public Button()
{
InitializeComponent();
}
Image img;
public Image Img
{
get { return img; }
set { img = value; this.Icon = img; }
}
string hTxt;
public string HTxt
{
get { return hTxt; }
set { hTxt = value; this.HoverText.Text = hTxt; }
}
}
}
(The function-selection is not implemented yet)
Here I call the usercontrol and try to set the property
xmlns:bt="clr-namespace:Messenger.Controls.MainWindow"
<StackPanel Name="spButtons" Height="30" VerticalAlignment="Top" Orientation="Horizontal">
<bt:Button Name="one" >
<bt:Button.HText >
Test
</bt:Button.HText>
</bt:Button>
<bt:Button Name="two" />
<bt:Button Name="tre" />
<bt:Button Name="for" />
</StackPanel>
But I get an error-message:
"The member "HText" is unknown or the member can't be accessed"
//"The attached "HText"-property can't be found in 'Button'" This message does not appear anymore
I have user control with dependency property. When I try bind it in windows it doesn't work. But when I change binding to normal parameter (in this situation, true) it's working. What i need to do to make my binding working? Maybe something with DataContext? Here is my code:
First user control's xaml:
<UserControl x:Class="DPTest.CustomUserControl"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="100" d:DesignWidth="200"
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<TextBlock Text="{Binding Property}"/>
</Grid>
</UserControl>
Code behind:
public partial class CustomUserControl : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty DPTestProperty = DependencyProperty.Register("DPTest", typeof(bool), typeof(CustomUserControl), new PropertyMetadata(default(bool), propertyChangedCallback));
public bool DPTest
{
get
{
return (bool)GetValue(DPTestProperty);
}
set
{
SetValue(DPTestProperty, value);
}
}
private bool _property;
public bool Property
{
get
{
return _property;
}
set
{
_property = value;
RaisePropertyChanged("Property");
}
}
private static void propertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as CustomUserControl;
control.Property = (bool)e.NewValue;
}
public CustomUserControl()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In the windows where i put this user control data context is set to my view model:
<phone:PhoneApplicationPage
x:Class="DPTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:my="clr-namespace:DPTest"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<my:CustomUserControl Name="cstom" DPTest="{Binding Property}"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
In the view model I have property which is binded to DPTest.
public class MainViewModel : ViewModelBase
{
private bool _property;
public bool Property
{
get { return _property; }
set
{
_property = value;
RaisePropertyChanged("Property");
}
}
public MainViewModel()
{
Property = true;
}
}
When I run this application Textblock have value False but this should be True and propertyChangedCallback isn't even called. What i need to do?
Thanks
Try this:
<UserControl x:Class="DPTest.CustomUserControl"
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" mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource
PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" d:DesignHeight="100"
d:DesignWidth="200"
x:Name="self">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<TextBlock Text="{Binding Property, ElementName=self}"/>
</Grid>
You have bind UserControl DataContext to itself since you want to bind Property present in CustomUserControl to TextBlock inside it which is completely fine.
But when you use CustomUserControl in Window, it won't inherit Window's DataContext since its explicitly set on UserControl declaration. So, binding engine is trying to look for property in UserControl which it can't fine.
Note: Binding engine looks for property inside it's DataContext otherwise instructed to look somewhere else using RelativeSource, ElementName, x:Reference etc.
So you need to manually provide binding engine the property instance like this:
<my:CustomUserControl Name="cstom"
DPTest="{Binding Path=DataContext.Property,
ElementName=LayoutRoot}"/>
Explanation for working with DPTest="True":
Since you already manually provided the value to DP, binding engine doesn't have to worry about finding it in DataContext.