WPF: binding to a dependency property - wpf

I am following a tutorial here. which shows a basic example on how to bind to a dependency property.
<Binding ElementName="This" Path="IPAddress" UpdateSourceTrigger="PropertyChanged">
where "This" is the name of the current window:
<Window x:Class="SOTCBindingValidation.Window1" x:Name="This"
whenever i try to do something like this, i keep getting the same error:
Cannot find source for binding with reference 'ElementName=GridControlControl1'. BindingExpression:Path=IPAddress; DataItem=null; target element is 'TextBox' (Name='AddressBox'); target property is 'Text' (type 'String')
my code:
<UserControl x:Class="WpfGridtest.GridControl" x:Name="GridControlControl1" ... />
<TextBox x:Name="AddressBox">
<TextBox.Text>
<Binding ElementName="GridControlControl1" Path="IPAddress" UpdateSourceTrigger="PropertyChanged">
</Binding>
</TextBox.Text>
</TextBox>
codebehind:
partial class GridControl : UserControl
public static readonly DependencyProperty IPAddressProperty = DependencyProperty.Register("IPAddress", typeof(string), typeof(GridControl), new UIPropertyMetadata("1.1.1.1"));
public string IPAddress
{
get { return (string)GetValue(IPAddressProperty); }
set { SetValue(IPAddressProperty, value); }
}
it's almost like something changed in .Net 4.0?

It depends on what you want. I'll try to offer a complete answer. One way to guarantee better success with this syntax is to use VS2010's XAML Binding Builder, which is how I assembled the syntax you're about to see.
If you want an element of the UserControl to display your IPAddress dependency property, (which looks like it's defined correctly to me), use this syntax within the body of the UserControl's markup:
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type my:GridControl},
AncestorLevel=1},
Path=IPAddress}" />
Most XAML binding examples use this syntax rather than the more verbose hierarchical XML:
<TextBlock>
<TextBlock.Text>
<Binding Path="IPAddress">
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor"
AncestorType="{x:Type my:GridControl}"
AncestorLevel="1"
/>
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
...but both kinds of syntax produce the same results. Note here that the AncestorType is the class name of your UserControl, not the x:Name you would supply when using the UserControl in other markup.
Suppose you have a UI element in markup outside your UserControl, and you want access to your DependencyProperty for that other control. The markup looks something like this:
<my:GridControl
x:Name="GridControl1" IPAddress="192.168.1.1" />
<TextBox Text="{Binding ElementName=GridControl1, Path=IPAddress}"/>
Or, alternatively, this:
<TextBox>
<TextBox.Text>
<Binding ElementName="GridControl1" Path="IPAddress"/>
</TextBox.Text>
</TextBox>
Note here that this time you're using the x:Name property of the GridControl rather than the class name, and that you refer to it as an ElementName, and not an "Ancestor". In both cases, though, the Path is the declared name of the DependencyProperty you defined.

Try using RelativeSource:
<TextBox>
<TextBox.Text>
<Binding Path="IPAddress">
<Binding.RelativeSource>
<RelativeSource
Mode="FindAncestor"
AncestorType="{x:Type UserControl}"
AncestorLevel="1"
/>
</Binding.RelativeSource>
</Binding>
</TextBox.Text>
</TextBox>
Instead of {x:Type UserControl}you could insert your actual type there, i.e.:
<TextBox>
<TextBox.Text>
<Binding Path="IPAddress">
<Binding.RelativeSource>
<RelativeSource xmlns:my="clr-namespace:WpfGridtest"
Mode="FindAncestor"
AncestorType="{x:Type my:GridControl}"
AncestorLevel="1"
/>
</Binding.RelativeSource>
</Binding>
</TextBox.Text>
</TextBox>

Related

Please guide me how to code tooltip in xaml

I never used WPF , tooltip before I am assigned to implement textbox that receieve number in range 1-999 if it out of this range tooltip will be shown near the textbox and textbox is changedto red border while input is out of range. pls guide me i try to bind xaml and function in C# but nothing happen
<TextBox HorizontalAlignment="Left" Height="31" TextWrapping="Wrap" VerticalAlignment="Top" Width="276" Margin="73,71,0,0" PreviewTextInput="PreviewTextInput" PreviewKeyDown="TextboxPreviewKeydown" >
<TextBox.Text>
<Binding Path="Number">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
and my C#
public int Number
{
get { return num; }
set
{
num = value;
if (value <= 0 || value >999)
{
throw new ApplicationException("Out of range");
}
}
In simplest way you can do this:
<TextBox Text="{Binding}">
<TextBox.ToolTip>
<TextBlock Text="{Binding }"/> // Here you can bind to property or give static value to show in tooltip
</TextBox.ToolTip>
</TextBox>
Thanks
What you need is to build a validation rule
You create a class ("MyValidation" for example) that extends "ValidationRule" and you implement it
Then in your xaml, you can do this
<TextBox>
<TextBox.Text>
<Binding...>
<Binding.ValidationRules>
<local:MyValidation/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

Observation collection not updating when multibinding

I have a static ObservableCollection MarketList in ViewModel and
it is bound to Table in following manner:
<FlowDocumentScrollViewer Height="216" VerticalAlignment="Top" Margin="-7,2,7,0" >
<FlowDocument>
<Table CellSpacing="0" Name="MBPTable" >
<Table.DataContext>
<MultiBinding UpdateSourceTrigger="Explicit" Mode="TwoWay" Converter="{StaticResource indexerConverter}">
<Binding Path="MarketList" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" Mode="TwoWay" BindsDirectlyToSource="True" />
<Binding Path="MBPindex" Mode="TwoWay" />
</MultiBinding>
</Table.DataContext>
<Table.Resources>
<local:IndexerConverter x:Key="indexerConverter"></local:IndexerConverter>
</Table.Resources>
Table contains ListView which is bound to Property of MarketList.
<ListView Name="MarketByPriceList" Width="300" ItemsSource="{Binding MarketByPriceList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" AlternationCount="2" Margin="0,15,0,0" >
<ListView.View>
<GridView>
<GridViewColumn Header="Orders" Width="48" DisplayMemberBinding="{Binding MBP_NoofBuy_Orders, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ></GridViewColumn>
<GridViewColumn Header="Bid Qty" Width="48" DisplayMemberBinding="{Binding MBPBID_Qty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
This Is Convertor Method
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values != null && values[0] != DependencyProperty.UnsetValue)
{
// ObservableCollection<GlobalItems.Model.MarketWatchModel> allNames = (ObservableCollection<GlobalItems.Model.MarketWatchModel>)values[0];
int index = (int)values[1];
return GlobalItems.ViewModel.MarketWatchModelView.MarketList[index];
}
else
{
return null;
}
}
Binding works fine but update in collection is not reflected in UI
This appears to boil down to the same problem described here, and essentially the same solution should work.
Updating (adding to or removing from) the ObservableCollection does not cause your MultiBinding to refresh because the MultiBinding is listening for a PropertyChanged event and updating an ObservableCollection only fires a CollectionChanged event. A clean workaround is to add a Binding to the Count property of your ObservableCollection in your MultiBinding. E.g.
<MultiBinding UpdateSourceTrigger="Explicit" Mode="TwoWay" Converter="{StaticResource indexerConverter}">
<Binding Path="MarketList" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" Mode="TwoWay" BindsDirectlyToSource="True" />
<Binding Path="MBPindex" Mode="TwoWay" />
<Binding Path="MarketList.Count" /> <!-- Additional Binding causes refresh when MarketList is updated -->
</MultiBinding>
Add the additional binding after all of your existing bindings so that the MultiValueConverter can just ignore the extra value. When the Count property of your ObservableCollection changes (when you add or remove items), then it will fire a PropertyChanged event and your MultiBinding will refresh.
I was troubleshooting the same issue, but needing it to fire not only when the count changed, but also when items were modified. Both Dan's answer and the one he linked got me pointed in the right direction, but along the way I discovered there is a better alternative to binding to the Count property. Bind to "Item[]" instead, which will fire a PropertyChange both when items are added or removed (same as Count), but also when items are rearranged or changed.
Updated version of Dan's example:
<MultiBinding UpdateSourceTrigger="Explicit" Mode="TwoWay" Converter="{StaticResource indexerConverter}">
<Binding Path="MarketList" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" Mode="TwoWay" BindsDirectlyToSource="True" />
<Binding Path="MBPindex" Mode="TwoWay" />
<Binding Path="MarketList.Item[]" /> <!-- This is the difference -->
</MultiBinding>
My source was the source code of ObservableCollection, found here: http://referencesource.microsoft.com/#System/compmod/system/collections/objectmodel/observablecollection.cs

Binding StringFormat

I have a collection of textblocks that I'm going to be showing and I'm needing the text of each textblock to be displayed differently. I'm currently saving the format string in the tag property and I'm needing to display the text in this format. How do I bind the StringFormat section?
Something like the section below:
<TextBlock Tag="{Binding MyFormatString}" Text="{Binding MyProperty, StringFormat='{}{0:MyTag}'}" />
Since BindingBase.StringFormat is not a dependency property, I do not think that you can bind it. If the formatting string varies, I'm afraid you will have to resort to something like this
<TextBlock Text="{Binding MyFormattedProperty}" />
and do the formatting in your view model. Alternatively, you could use a MultiBinding and a converter (example code untested):
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource myStringFormatter}">
<Binding Path="MyProperty" />
<Binding Path="MyFormatString" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
public class StringFormatter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return string.Format((string)values[1], values[0]);
}
...
}
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0},{1}">
<Binding Path="MyProperty" />
<Binding Path="MyFormatString" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The String Formatting is a display setting and therefore should live close to the UI layer, you can either declare it in the Xaml or have formatted string properties on a ViewModel and perform the formatting in the Get of those properties and bind the TextBlock to it the ViewModel properties. It would source its data from the original datasource.

Converters on child bindings in a MultiBinding

Suppose I have this MultiBinding:
<MultiBinding Converter="{StaticResource FooBarConverter}>
<Binding Path="Foo" Converter="{StaticResource FooConverter}" />
<Binding Path="Bar" Converter="{StaticResource BarConverter}" />
</MultiBinding>
This doesn't seem to work: the values array passed to FooBarConverter contains DependencyProperty.UnsetValue for each value (two, in this case). Removing the converters on the child bindings (FooConverter and BarConverter) gives me the actual values. By the way: those converters are properly invoked, it just looks like their result is discarded.
Is this intended behavior? I want to bind 2 properties by I need to convert at least one of them before throwing them into the MultiValueConverter...
The developers in Kishore's shared link came to the conclusion that to make such a MultiBinding, the child Bindings must return the same type of result as the parent MultiBinding. So, in my case, if I wanted the parent MultiBinding to return a value of type Visibility, the child Bindings must also return Visibility values. Not doing so will pass UnsetValues to your converter method, likely giving you undesireable results.
Here is a snippet of code that works for me. Note that Converters "VisibleIfTrue" and "EnumToVisibility" both return type Visibility values:
<Grid.Visibility>
<MultiBinding Converter="{StaticResource MultiVisibilityConverter}">
<Binding Path="JobHasData" Converter="{StaticResource VisibleIfTrue}" />
<Binding Path="CurrentMode" Converter="{StaticResource EnumToVisibility}" ConverterParameter="{x:Static Mode.Setup}" />
</MultiBinding>
</Grid.Visibility>
It is annoying that you can't pass it different value types to process and give you the result you want. (I initially tried to pass bools to the converter.)
Hope this helps anyone who waited the seven years for the answer. ;)
you have mention converter in the Multibinding tag like this
<TextBlock Grid.Row="3" Grid.Column="1" Padding="5">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource sumConverter}">
<Binding Path="FirstNum" />
<Binding Path="SecondNum" />
<Binding Path="ThirdNum" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
If WPF was prior to 4.0 then it is a known and fixed bug that have workaround.
Here located a sample implementation of the workaround for poor man that are forced to work with elder versions.
To say shortly, old wpf versions are trying to convert values from multibinding child bindings that have converters directly into type of target dependency property. Workaround is to create hidden label, move multibinding or its child binding converter to label.content as it expects object and then bind desired property to it.
public class DataClass
{
public string FirstName { get; set; }
public string Surname { get; set; }
}
public class NameMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return String.Format("{0} {1}", values[0], values[1]);
}
}
The XAML looks basically like this
<Window xmlns:local="clr-namespace:BlogIMultiValueConverter">
<Window.Resources>
<local:NameMultiValueConverter x:Key="NameMultiValueConverter" />
</Window.Resources>
<Grid>
<TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Path=Surname, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding Path="FirstName" />
<Binding Path="Surname" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>

WPF - Converter hides dependency on a DependencyProperty

I have a TextBlock (acutally a whole bunch of TextBlocks) where I set the Text to "" if a DependencyProperty in my ViewModel is set to Visiblity.Hidden. I do this via a converter as follows:
<TextBlock Margin="0,0,5,0">
<TextBlock.Text>
<Binding Converter="{StaticResource GetVisibilityOfColumnTitles}"
Path="Name" />
</TextBlock.Text>
</TextBlock>
The converter looks like this:
public object Convert(object value, Type targetType,
object parameter,System.Globalization.CultureInfo culture)
{
if (MainMediator.Instance.VisibilityOfWorkItemColumnTitles
== Visibility.Visible)
return value;
else
return "";
}
I admit that this is a bit convoluted way to do this, but I have my reasons (DataContext complications and spacing for the TextBlock)
The problem I have is that when VisibilityOfWorkItemColumnTitles is changed, even though it is a dependency property, TextBlock.Text does not realize there is a dependency there (because it's used in the converter).
Is there a way in the code behind (preferably in the converter) to say, this TextBlock wants to update this binding when VisibilityOfWorkItemColumnTitles changes?
Since your converter depends on both the Text property from the TextBox and the VisibilityOfWorkItemColumnTitles property on your MainMediator class, you'll probably need to use a MultiBinding and include both properties back in the XAML.
<TextBlock Margin="0,0,5,0">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource GetVisibilityOfColumnTitles}">
<Binding Path="Name" />
<Binding Path="VisibilityOfWorkItemColumnTitles" Source="{x:Static my:MainMediator.Instance}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
(I've used "my" as the XML namespace for your MainMediator class in that code sample.)
Then change your converter to an IMultiValueConverter, and reference values[0] for the text and values1 for the "visibility" property. Now the binding will know if either property changes, and call off to the converter appropriately.

Resources