MultiBinding to the Title Property of a wpf user control? - wpf

I need to format the Title property of my user control. For this I am trying to make use of MultiBinding with StringFormat.
The Xaml I use is :
<Control x:Name="myControlName">
<Control.Title>
<MultiBinding StringFormat="You have {0} of {1} items. ">
<Binding Path="MyNumber"></Binding>
<Binding Path="TotalNumber"></Binding>
</MultiBinding>
</Control.Title>
</Control>
For some reason this does not seem to work.
Am I missing something here? Thanks!

I would recommend binding the Title property to a property on a ViewModel if using MVVM or just a property on the code behind if not.
<Control x:Name="myControlName" Title={Binding Path=MyTitle}>
</Control>
public class MyView
{
public int MyNumber { get; set; }
public int TotalNumber { get; set; }
public string MyTitle
{
get { return string.Format("You have {0} of {1} items. ", MyNumber, TotalNumber); }
}
}

Related

WPF ToggleButton multibinding of IsChecked through MarkupExtension throws

I am trying to bind the IsChecked property of a ToggleButton through a markup extension which resolves to a MultiBinding. In XAML I have two source toggle buttons and a target toggle button which should have its IsChecked bound to the IsChecked of the source buttons.
<ToggleButton x:Name="Source1" Content="Source 1" Margin="5" Padding="5,2"/>
<ToggleButton x:Name="Source2" Content="Source 2" Margin="5" Padding="5,2"/>
<ToggleButton Content="Target" Margin="5" Padding="5,2">
<ToggleButton.IsChecked>
<local:ExMultiBinding Converter="{StaticResource AnyConverter}">
<Binding ElementName="Source1" Path="IsChecked"/>
<Binding ElementName="Source2" Path="IsChecked"/>
</local:ExMultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
My markup extension providing the MultiBinding looks like this
[ContentProperty("Bindings")]
public class ExMultiBindingExtension : MarkupExtension, INotifyPropertyChanged
{
public Collection<BindingBase> Bindings { get; set; } = new Collection<BindingBase>();
public IMultiValueConverter Converter { get; set; }
public BindingMode Mode { get; set; }
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var multi = new MultiBinding
{
Converter = Converter,
Mode = Mode,
UpdateSourceTrigger = UpdateSourceTrigger
};
return multi;
}
public event PropertyChangedEventHandler PropertyChanged;
}
Starting the UI yields
ArgumentException: 'System.Windows.Data.MultiBinding' is not a valid value for property 'IsChecked'.
I checked and the IsChecked property on the ToggleButton implementation is actually not marked with
[Bindable(true)]
but only with
[Category("Appearance")]
[TypeConverter(typeof (NullableBoolConverter))]
[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
Direct binding through a Binding or MultiBinding in XAML works.
The example code is simplified to highlight the problem. It is not possible to avoid the MarkupExtension in the real code since the implementation is more complicated.
BindingBase itself is a MarkupExtension. And of course a markupExtension is not of type bool and can't be assigned to a member of type bool.
The reason why your extension is called is because the XAML parser wants to resolve every MarkupExtension. It's done by invoking the MarkupExtension.ProvideValue method. In this case the BindingBase object will be associated with a BindingExpressionBase object. This BindingExpressionBase will resolve the underlying binding to return the actual value (simplified).
So you have to manually resolve the BindingBase markup:
public override object ProvideValue(IServiceProvider serviceProvider)
{
var multi = new MultiBinding
{
Converter = Converter,
Mode = Mode,
UpdateSourceTrigger = UpdateSourceTrigger
};
// Resolve the MarkupExtension BindingBase
return multi.ProvideValue(serviceProvider);
}

Binding ReactiveList to ComboBox couldn't find view error

I am binding a ReactiveList to a ComboBox in the view code-behind and get the error System.Exception: 'Couldn't find view for 'Value1'.'.
ViewModel.cs
public class SourceItem
{
public override string ToString()
{
return Name;
}
public string Name { get; set; }
}
public class ViewModel : ReactiveObject
{
public ReactiveList<SourceItem> SourceList { get; } = new ReactiveList<SourceItem>();
public SourceItem SelectedSourceItem { get; set; }
public ViewModel()
{
SourceList.Add(new SourceItem() {Name = "Value1"});
}
}
View.xaml
<ComboBox Name="Source"/>
View.cs
this.OneWayBind(ViewModel, x => x.SourceList, x => x.Source.ItemSource);
this.Bind(ViewModel, x => x.SelectedSourceItem, x => x.Source.SelectedItem);
Is there a simple way to force ToString() to be used for the display values?
Regular Binding will automatically work without a DataTemplate. It will generate a DataTemplate to display a string representation of the provided data.
RxUI bindings does not work that way; you have to provide a DataTemplate for them to work:
<ComboBox Name="Source">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
When just using {Binding} it should fall back to calling ToString() on your class. Alternatively you can of course tell it to bind to the Name property manually:
<TextBlock Text="{Binding Name}"/>

How to set a TimeSpan in Xaml

I am unable to set a property of type TimeSpan from xaml on my dependency object and am looking for if there's a way to get this to work.
Xaml: <local:MyDependencyObject Time="00:00:05"/>
Time is a dependency property of type TimeSpan.
Please tell me how can I set a dependency property of type (TimeSpan) in xaml.
TotalMinutes is a Double, but the D format specifier is only supported for integral types such as Int32. A format string such as {}{0:D1} h {1:D1} min ({2} min) should work.
OR
Try This way :
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:D2}:{1:D2}">
<Binding Path="MyTime.Hours" />
<Binding Path="MyTime.Minutes" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
I Did it from code Behind.
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
MessageBox.Show(IsSpinning.ToString());
}
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(TimeSpan),
typeof(TimeSpan), null
);
public TimeSpan IsSpinning
{
get { return (TimeSpan)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
}

Binding to Property of a ComboBox's SelectedItem

I am having a hard time finding the right syntax for binding to a ComboBox's SelectedItem's property. This is the XAML I am trying to use for the binding. Where you see SelectedItem.Mode is the idea I am having difficulty with. Note that CurrentMode is in the ViewModel and has the same type as SelectedItem.Mode
<ComboBox SelectedItem.Mode="{Binding Path=CurrentMode, Mode=TwoWays}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImageSource}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<local:ModeItem Mode="Free" ImageSource="pencil.png"/>
<local:ModeItem Mode="Arrow" ImageSource="arrow.png"/>
</ComboBox>
A local:ModeItem looks like this
public class ModeItem : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty ModeProperty = DependencyProperty.Register("Mode", typeof(AnnotationMode), typeof(ModeItem));
public AnnotationMode Mode
{
get { return (AnnotationMode)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
public string ImageSource { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
I am using MVVM and trying to bind the AnnotationMode (CurrentMode) of the ViewModel to that of the ComboBox's SelectedItem's AnnotationMode (Mode)
Just do this
SelectedItem="{Binding CurrentMode}
You don't have to do all this extra stuff you are doing. Note You do need to make the datacontext of the combobox is pointing to your viewmodel.
Edit :-
You should be able to do this
SelectedValue="{Binding CurrentMode, Mode=TwoWay}"
SelectedValuePath="Mode"

MVVM Property for datagrid itemssource

I have a datagrid whose itemsSource is bound to a multiconverter which uses a converter.
<toolkit:DataGrid AutoGenerateColumns="False">
<toolkit:DataGrid.ItemsSource>
<MultiBinding Converter="{StaticResource ProfileConverter}">
<Binding ElementName="ComboBoxProfiles" Path="SelectedValue" />
<Binding ElementName="DatePickerTargetDate" Path="SelectedDate" />
</MultiBinding>
</toolkit:DataGrid.ItemsSource>
This is good because the itemsSource of the grid is updated whenever the combobox or datepicker changes value.
The problem I now have is that in my ViewModel I want to be able to access the ItemSource of my datagrid and either remove items for the list or add new ones.
How do I get access to the itemssource when I have it set up like this?
Many thanks.
How about having three properties in the ViewModel:
public DateTime? SelectedDate
{
get{return _selectedDate;}
set
{
_selectedDate = value;
UpdateItemsSource();
OnPropertyChanged("SelectedDate");
}
}
public object SelectedComboBoxValue
{
get{return _selectedComboBoxValue;}
set
{
_selectedComboBoxValue= value;
UpdateItemsSource();
OnPropertyChanged("SelectedComboBoxValue");
}
}
private void UpdateItemsSource()
{
_itemsSource = //Some fancy expression based on the two fields.
OnPropertyChanged("ItemsSource");
}
public IEnumerable ItemsSource
{
get{return _itemsSource;}
}
Then bind the datepicker, combobox and datagrid to the respective values.
Hope this helps.

Resources