How do I get DependencyProperty to work in Silverlight? - silverlight

I'm trying to bind using a DependencyProperty, but I can't even get the DependencyProperty to work let alone try to bind to it.
I'm following a silverlight guide and up to this point I'm supposed to be able to set the property using XAML. Here is the code I have so far:
MainPage.xaml:
<UserControl
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:UserControlSample" x:Class="UserControlSample.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<local:InfoRectangle Margin="32,36,0,0" HorizontalAlignment="Left" Height="70" VerticalAlignment="Top" Width="122" InfoText="New Text"/>
<local:InfoRectangle Margin="105,139,188,97" InfoText="some text" />
</Grid>
InfoRectangle.xaml:
<UserControl
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
mc:Ignorable="d"
x:Class="UserControlSample.InfoRectangle"
d:DesignWidth="122" d:DesignHeight="70">
<Grid x:Name="LayoutRoot">
<Rectangle Fill="#FFABABE9" Stroke="Black" RadiusY="4" RadiusX="4"/>
<TextBlock Name="InfoLabel" Text="Text block" Margin="5" />
</Grid>
InfoRectangle.xaml.cs:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace UserControlSample
{
public partial class InfoRectangle : UserControl
{
public InfoRectangle()
{
// Required to initialize variables
InitializeComponent();
}
public string InfoText
{
get { return (string)GetValue(InfoTextProperty); }
set { SetValue(InfoTextProperty, value); }
}
public static readonly DependencyProperty InfoTextProperty =
DependencyProperty.Register(
"InfoText",
typeof(string),
typeof(InfoRectangle),
new PropertyMetadata("something", InfoTextChanged));
private static void InfoTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
When I run the solution the two rectangles show up but they display just "Text block" which is neither the default set or the value set in the MainPage XAML for the user controls.

My answer in here details a nice compact example of a dependency property updating a given property on a view model. The property on your view model would be bound to your text block so once change notification fires, your text block should update.

Here is the solution;
It seems the callback method has to be completed.
private static void InfoTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((InfoRectangle)d).InfoLabel.Text = e.NewValue.ToString();
}

Related

WPF - MVVM binding in UserControl

I'm testing a sample binding in MVVM pattern. I'm using package GalaSoft.MvvmLight. Binding from MainViewModel to MainWindow is normal but I can't binding data from a ViewModel (ImageViewModel) to View (ImageView). All my code is below
in App.xaml
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-
namespace:WpfApplication1" StartupUri="MainWindow.xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d"
xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-
namespace:WpfApplication1.ViewModel" />
</ResourceDictionary>
</Application.Resources>
</Application>
in MainWindow.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:v="clr-namespace:WpfApplication1.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
DataContext="{Binding Main, Source={StaticResource Locator}}"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="1000">
<Grid>
<Grid Grid.Column="1">
<v:ImageView DataContext="{Binding ImageVM}"/>
</Grid>
</Grid>
in ImageView.xaml
<UserControl x:Class="WpfApplication1.View.ImageView"
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:WpfApplication1.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="ucImage">
<UserControl.DataContext>
<Binding Path="Main.ImageVM" Source="{StaticResource Locator}"/>
</UserControl.DataContext>
<Grid>
<TextBox x:Name="label" Text="{Binding TestText, ElementName=ucImage}" Width="100"
Height="50"/>
</Grid>
</UserControl>
in ViewModelLocator.cs
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication1.ViewModel
{
public class ImageViewModel: ViewModelBase
{
public string _TestText;
public string TestText
{
get
{
return _TestText;
}
set
{
_TestText = value;
RaisePropertyChanged(() => this.TestText);
}
}
public ImageViewModel()
{
TestText = "asdasdasdasdas";
}
}
}
in MainViewModel
public class MainViewModel : ViewModelBase
{
private ImageViewModel _ImageVM;
public ImageViewModel ImageVM
{
get { return _ImageVM; }
set { Set(ref _ImageVM, value); }
}
public MainViewModel()
{
ImageVM = new ImageViewModel();
}
}
in ImageViewModel.cs
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication1.ViewModel
{
public class ImageViewModel: ViewModelBase
{
public string _TestText;
public string TestText
{
get
{
return _TestText;
}
set
{
_TestText = value;
RaisePropertyChanged(() => this.TestText);
}
}
public ImageViewModel()
{
TestText = "asdasdasdasdas";
}
}
}
This error from output is
System.Windows.Data Error: 40 : BindingExpression path error:
'TestText' property not found on 'object' ''ImageView'
(Name='ucImage')'. BindingExpression:Path=TestText;
DataItem='ImageView' (Name='ucImage'); target element is 'TextBox'
(Name='label'); target property is 'Text' (type 'String')
Anyone who comes up with a solution would be greatly appreciated!
The expression
Text="{Binding TestText, ElementName=ucImage}"
expects a TestText property in the ImageView control, which apperently does not exists - that is what the error message says.
You would simply write the following to make the element in the control's XAML bind directly to the view model object in its DataContext:
<TextBox Text="{Binding TestText}" .../>
In order to make the control independent of a specific view model, it should expose a bindable property, i.e. a dependency property like this:
public partial class ImageView : UserControl
{
public ImageView()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
nameof(Text), typeof(string), typeof(ImageView));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
which would work with
<TextBox Text="{Binding Text, ElementName=ucImage}"
in the control's XAML and without explictly setting the control's DataContext, i.e. without the <UserControl.DataContext> section in its XAML.
The property would be bound like
<v:ImageView DataContext="{Binding ImageVM}" Text="{Binding TestText}"/>
or just
<v:ImageView Text="{Binding ImageVM.TestText}"/>

How can I bind the value cross the window?

Here is the 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="MainWindow" Height="450" Width="800">
<Grid>
<TextBox Text="{Binding CB+Width,RelativeSource={RelativeSource AncestorType={x:Type Window}},Mode=TwoWay}"></TextBox>
</Grid>
</Window>
And here is code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TB = new TextBox();
TB.Width = 200;
}
public ComboBox CB
{
get { return (ComboBox)GetValue(CBProperty); }
set { SetValue(CBProperty, value); }
}
// Using a DependencyProperty as the backing store for CB. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CBProperty =
DependencyProperty.Register("CB", typeof(ComboBox), typeof(MainWindow), null);
}
}
In fact, the DependencyProperty is a custom control, but I replace it as a ComboBox for easy to explain my problem to you.
The custom control is not in the same window and I want to bind its value such as Width to the TextBox.
The custom control is in a different window. That means there are two windows, window 1 and window 2. The custom control is in window 1 and the textbox is in window 2. I do this because one is the main window and the other is the setting window. Whenever the setting window changes the setting, you can see it in the main window at once. So I use a DependencyProperty to store the custom control which in a different window and wanna bind it to the textbox.
Now how can I do it? Would you please help me? Thank you.
It LOOKs like you want your textbox to show the width property of the Window? (or some other control in the future and just testing). If you apply an x:Name value to a control, you can reference that control directly in the XMAL and then properties directly on that. No need for any custom other control with your own dependency property... something like.
<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="MainWindow" Height="450" Width="800"
x:Name="myOuterWindowControl" >
<Grid>
<TextBox Text="{Binding ElementName=myOuterWindowControl, Path=Width, Mode=TwoWay,
UpdateSourceTrigger=LostFocus}" Height="30" Width="70"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Height="30" Width="70"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,50,0,0"/>
</Grid>
</Window>
Now I actually added an extra textbox control so there is more than one control in the XAML to allow focus to change. Reason. I set the textbox to allow mode as Two-Way binding. The window will push to the textbox, but you can also type in a value to the textbox and when the LOST FOCUS happens, it pushes the value back to the window and you can dynamically change the width (or other property height, coloring, whatever).
Is this more in line with what you were trying to get at?

Display Images (Binding) in Silverlight

I need to solve following issue: In a Silverlight app, the user needs to be able to upload images to the client (not the server). The images should be displayed in a wrappanel.
I am a complete rookie to silverlight, so you might find several mistakes in the code. Below I posted the code, I hope it is sufficient to answer the question!
App.xaml:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
x:Class="Dojo_3_wi10b012.App"
>
<Application.Resources>
<local:ViewModel x:Key="viewModel"/>
</Application.Resources>
</Application>
MainPage.xaml:
<UserControl x:Class="Dojo_3_wi10b012.MainPage"
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource viewModel}">
<sdk:Frame Height="350" Width="450"
Name="frameContainer" Margin="0,0,0,0">
</sdk:Frame>
<Button Content="Add Image" Command="{Binding Path=AddImageCommand}" Height="23" HorizontalAlignment="Left" Margin="468,454,0,0" Name="buttonAddImage" VerticalAlignment="Top" Width="75" />
</Grid>
</UserControl>
Gallery.xaml:
<navigation:Page x:Class="Dojo_3_wi10b012.View.Gallery"
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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:Dojo_3_wi10b012.ViewModel"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="640" d:DesignHeight="480"
Title="Gallery Page"
NavigationCacheMode="Required" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<!-- trying to implement Mr. Eckkrammer's hint (wiki)-->
<UserControl.Resources>
<DataTemplate x:Key="galleryTemplate">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Image}"/>
</Image.Source>
</Image>
</DataTemplate>
</UserControl.Resources>
<!-- END OF trying to implement Mr. Eckkrammer's hint (wiki)-->
<Grid x:Name="LayoutRoot" Height="350" Width="450" Background="Beige" DataContext="{StaticResource viewModel}">
<!-- "First attempt
<ItemsControl ItemsSource="{Binding ElementName=ImageDescrList, Path=Image ,Mode=TwoWay}" >
<ScrollViewer Width="449" Height="349" Margin="1,1,0,0">
<toolkit:WrapPanel Orientation="Horizontal" ItemWidth="90" ItemHeight="90" Width="Auto" />
</ScrollViewer>
</ItemsControl>
-->
<!-- 2nd attempt (Mr. Eckkrammer's hint (wiki): -->
<ItemsControl ItemsSource="{Binding ElementName=ImageDescrList}" ItemTemplate="{StaticResource galleryTemplate}">
<ScrollViewer Width="449" Height="349" Margin="1,1,0,0">
<toolkit:WrapPanel Orientation="Horizontal" ItemWidth="90" ItemHeight="90" Width="Auto" />
</ScrollViewer>
</ItemsControl>
</Grid>
</navigation:Page>
ImageDescription.cs:
namespace Dojo_3_wi10b012.Model
{
public class ImageDescription : INotifyPropertyChanged
{
private string _description;
private BitmapImage _image;
public string Description
{
get { return _description; }
set
{
_description = value;
NotifyPropertyChanged("Description");
}
}
public BitmapImage Image
{
get { return _image; }
set
{
_image = value;
NotifyPropertyChanged("Image");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
ViewModel.cs:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Media.Imaging;
using System.Collections;
using System.Collections.ObjectModel;
using Dojo_3_wi10b012.Model;
using System.ComponentModel;
namespace Dojo_3_wi10b012.ViewModel
{
public class ViewModel : INotifyPropertyChanged
{
public RelayCommand AddImageCommand { get; private set; }
private ObservableCollection<ImageDescription> _imageDescrList = new ObservableCollection<ImageDescription>();
#region properties
public ObservableCollection<ImageDescription> ImageDescrList
{
get { return _imageDescrList; }
set
{
_imageDescrList = value;
NotifyPropertyChanged("ImageDescrList");
}
}
#endregion
#region Constructor
public ViewModel()
{
AddImageCommand = new RelayCommand(AddImage);
AddImageCommand.IsEnabled = true;
}
#endregion
#region private methods
private void AddImage()
{
//initial ideas: (copy paste + modified from source: http://msdn.microsoft.com/en-us/library/cc221415(v=vs.95).aspx )
// Create an instance of the open file dialog box.
OpenFileDialog openFileDialog1 = new OpenFileDialog();
// Set filter options and filter index.
openFileDialog1.Filter = "JPEG Files (.jpg)|*.jpg|PNG Files (.png)|*.png|GIF Files (.gif)|*.gif|BMP Files (.bmp)|*.bmp|TIFF Files (.tiff)|*.tiff";
openFileDialog1.FilterIndex = 1;
openFileDialog1.Multiselect = false;
// Call the ShowDialog method to show the dialog box.
bool? userClickedOK = openFileDialog1.ShowDialog();
// Process input if the user clicked OK.
if (userClickedOK == true)
{
// Open the selected file to read.
using (var filestream = openFileDialog1.File.OpenRead())
{
var buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
//add the image to our list of images
MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length);
BitmapImage temp = new BitmapImage();
temp.SetSource(ms);
ImageDescrList.Add(
new ImageDescription()
{
// Description = filestream.Name,
Description="Default Description",
Image = temp
}
);
ms.Close();
filestream.Close();
}
}
}
#endregion
#region event Handler (property changed)
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Try this in your galleryTemplate template to bind the Image Source to your bitmap:
<DataTemplate x:Key="galleryTemplate">
<Image Source="{Binding Image}"/>
</DataTemplate>
You appear to be trying to bind a bitmap UriSource to a Bitmap instead (that would expect a Uri):
<DataTemplate x:Key="galleryTemplate">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Image}"/>
</Image.Source>
</Image>
</DataTemplate>

silverlight binding combobox in nested controls

I have 2 user controls one named Filters and one named FilterItem
Filter looks like this:
<UserControl xmlns:my="clr-namespace:AttorneyDashboard.Views.UserControls" x:Class="AttorneyDashboard.Views.UserControls.Filters"
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:helpers="clr-namespace:AttorneyDashboard.Helpers"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="590" x:Name="FiltersRoot">
<Grid>
<ListBox x:Name="myListBox" ItemsSource="{Binding Path=FilterItems, ElementName=FiltersRoot}" >
<ListBox.ItemTemplate>
<DataTemplate>
<my:FilterItem ColumnsList="{Binding Path=Columns_, ElementName=FiltersRoot}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Diagnostics;
using AttorneyDashboard.Helpers;
namespace AttorneyDashboard.Views.UserControls
{
public class MyItems
{
public string Header { get; set; }
}
public partial class Filters : UserControl
{
public Filters()
{
InitializeComponent();
}
private DependencyProperty FilterItemsProperty = DependencyProperty.Register("FilterItems", typeof(ObservableCollection<FilterDescriptor>), typeof(Filters), new PropertyMetadata(null, new PropertyChangedCallback(OnChangeFilterItems)));
public ObservableCollection<FilterDescriptor> FilterItems
{
get
{
return (ObservableCollection<FilterDescriptor>)GetValue(FilterItemsProperty);
}
set
{
SetValue(FilterItemsProperty, value);
}
}
public static void OnChangeFilterItems(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public List<MyItems> Columns_
{
get
{
List<MyItems> list = new List<MyItems>();
list.Add(new MyItems() { Header = "test1" });
list.Add(new MyItems() { Header = "test2" });
list.Add(new MyItems() { Header = "test3" });
return list;
}
}
}
}
FilterItems looks like this
<UserControl x:Class="AttorneyDashboard.Views.UserControls.FilterItem"
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"
d:DesignHeight="23" d:DesignWidth="590" xmlns:my="clr-namespace:AttorneyDashboard.Helpers" x:Name="FilterItemRoot">
<StackPanel Orientation="Horizontal">
<ComboBox Height="23" HorizontalAlignment="Left" Name="FieldName" VerticalAlignment="Top" Width="120" Margin="5,0,0,0" ItemsSource="{Binding Path=ColumnsList, ElementName=FilterItemRoot}" SelectedItem="{Binding PropertyPath, Mode=TwoWay}" DisplayMemberPath="Header"/>
</StackPanel>
</UserControl>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using AttorneyDashboard.Helpers;
using System.Windows.Data;
namespace AttorneyDashboard.Views.UserControls
{
public partial class FilterItem : UserControl
{
public FilterItem()
{
InitializeComponent();
}
private DependencyProperty ColumnsListProperty = DependencyProperty.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem), new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
public List<MyItems> ColumnsList
{
get
{
return (List<MyItems>)GetValue(ColumnsListProperty);
}
set
{
SetValue(ColumnsListProperty, value);
}
}
public static void OnChangeColumns(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
The number of FilterItems is ok (this means that FilterItems binding works ok), but only the Combobox of the last FilterItem is populated...
And I do not know what exactly is wrong...
Update:
I found why but I stll do not know a solution...
It seams that the content of FilterItem is binded before his properties are..
So the combobox in FilterItem is binded before the Columns property is binded...
Your code in FilterItem
private DependencyProperty ColumnsListProperty = DependencyProperty
.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem),
new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
Please, make it static:
private **static** DependencyProperty ColumnsListProperty = DependencyProperty
.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem),
new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
Thats it.
P.S. : in Filters make dependency property static too, generally do it anywhere :)
You have placed a x:Name attribute directly on your UserControl elements. Don't do that. Use this pattern instead:-
<UserControl x:Class="AttorneyDashboard.Views.UserControls.FilterItem"
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"
d:DesignHeight="23" d:DesignWidth="590" xmlns:my="clr-namespace:AttorneyDashboard.Helpers" >
<StackPanel Orientation="Horizontal" x:Name="LayoutRoot">
<ComboBox Height="23" HorizontalAlignment="Left" Name="FieldName" VerticalAlignment="Top" Width="120" Margin="5,0,0,0" ItemsSource="{Binding Path=Parent.ColumnsList, ElementName=LayoutRoot}" SelectedItem="{Binding PropertyPath, Mode=TwoWay}" DisplayMemberPath="Header"/>
</StackPanel>
</UserControl>
You are not in control of name assigned to the user control, that belongs in the scope of the Xaml the uses your UserControl. If your code internally requires that the containing UserControl have a specific name then things are likely to break.

How can I access DependencyProperty values from my code-behind constructor?

I have a UserControl called SmartForm which has a DependencyProperty called Status.
In my Window1.xaml, I have the element <local:SmartForm Status="Ready"/>.
I would think then in the constructor of the SmartForm object, that Status would equal "Ready" but instead it equals null.
Why is then the value of the Status property NULL in the constructor of SmartForm?
If not in the UserControl constructor, when do I have access to the value, then?
Window1.xaml:
<Window x:Class="TestPropertyDefine23282.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestPropertyDefine23282"
Title="Window1" Height="300" Width="300">
<Grid>
<local:SmartForm Status="Ready"/>
</Grid>
</Window>
SmartForm.xaml:
<UserControl x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="TestingMessage"/>
</Grid>
</UserControl>
SmartForm.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace TestPropertyDefine23282
{
public partial class SmartForm : UserControl
{
public SmartForm()
{
InitializeComponent();
TestingMessage.Text = Status; //WHY IS STATUS NOT YET SET HERE?
}
#region DependencyProperty: Status
public string Status
{
get
{
return (string)GetValue(StatusProperty);
}
set
{
SetValue(StatusProperty, value);
}
}
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(SmartForm),
new FrameworkPropertyMetadata());
#endregion
}
}
<local:SmartForm Status="Ready"/>
Translates to:
SmartForm f = new SmartForm();
f.Status = Status.Ready;
You will have access to that value when the setter is called.
You can set that testing message as:
...
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(SmartForm),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnStatusChanged)));
public static void OnStatusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
((SmartForm)d).TestingMessage.Text = e.NewValue.ToString();
}
...
Or as:
<UserControl
x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestPropertyDefine23282"
Height="300" Width="300"
>
<Grid>
<TextBlock
x:Name="TestingMessage"
Text="{Binding Path=Status, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SmartForm}}}"
/>
</Grid>
</UserControl>
Szymon Rozga exlained the problem in a great way. You check the parameter before it is set but after the constructor is initialized.
A good solution is using the loaded event instead like so:
(Untested)
public SmartForm()
{
InitializeComponent();
Loaded += (sender, args) =>
{
TestingMessage.Text = Status;
};
}
This is kind of tertiary, but why do you need this setter at all?
<UserControl x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Control"
Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding Path=Status, ElementName=Control}" />
</Grid>
</UserControl>

Resources