Why MenuItem doesn't send specified parameters but Button send - wpf

<MenuItem Command="local:CommandLibrary.RegisterServiceCommand">
<MenuItem.CommandParameter>
<MultiBinding Converter="{StaticResource TrayWindowViewModelConverterResource}">
<MultiBinding.Bindings>
<Binding ElementName="Me" />
<Binding FallbackValue="Parser" />
</MultiBinding.Bindings>
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
public class TrayWindowViewModelConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
var viewModel = new Window1ViewModel();
foreach (var obj in values) {
if (obj is Window)
viewModel.Caller = obj as Window;
else if (obj is string)
viewModel.ServiceName = obj.ToString();
}
return viewModel;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Button cammand is exactly same as MenuItem. when i debug Converter for MenuItem, values parameter contains two object: DependencyProperty.UnsetValue (I'm not aware what's this) and MyContextMenu object.
And also how can i pass SomeType as parameter?
Thanks

MenuItems exist in popups that are outside the main visual tree and so don't have the same name scope as surrounding elements, like your Button. When trying to bind, the ElementName binding can't resolve because the "Me" element is outside the MenuItem's name scope.

Related

WPF - Image source with MultiBinding

In WPF, How to use Image source with Multi:
<Image x:Name="imgLane1" HorizontalAlignment="Left" Height="25" Margin="180,225,0,0" VerticalAlignment="Top" Width="42" Stretch="Fill">
<Image.Source>
<MultiBinding Converter="StaticResource LaneImageConverter}" UpdateSourceTrigger="PropertyChanged">
<Binding Path="Attachments">
<Binding Path="Delivery"/>
</MultiBinding>
</Image.Source>
</Image>`
public class LaneImageConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string path = "";
int attachments = 0;
string delivery = values[1].ToString();
Int32.TryParse(values[0].ToString(), out attachments);
return System.Windows.Data.Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I can not update imageSource with MultiBinding also debug to update source
Please help me ?
The converter must return an instance of a class that is derived from ImageSource, e.g. a BitmapImage that is loaded from the path of an image file:
public object Convert(
object[] values, Type targetType, object parameter, CultureInfo culture)
{
string path = "";
// compose path from values
return new BitmapImage(new Uri(path));
}
When the image file is a assembly resource, you would use a Resource File Pack URI:
var uri = string.Format("pack://application:,,,/images/{0}{1}.png", values); // for example
return new BitmapImage(new Uri(uri));

WPF MVVM Multibinding - How to pass two parameters to Command using RelayCommand

How to pass 2 parameters to command using RelayCommand. I need to pass COntrols as parameters (Grid and Window). I'm fully aware that such kind of problem has already existed on Stack Overflow but I'm struggling with adjusting that to my needs.
See look my first attempt is following. It obviously doesn't work because the Relay can't get 2 arguments.
Xaml code:
<Button Name="StretchScreenBtn" Content="Stretch screen" DataContext=" {StaticResource CommandWindow}" Command="{Binding ResizeScreenCommand}"
Width="100" Height="50">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource CommandParamsConv}">
<Binding ElementName="ScreenGrid" />
<Binding RelativeSource="{RelativeSource AncestorType=Window}" />
</MultiBinding>
</Button.CommandParameter>
</Button>
The Command code from ViewModel:
private ICommand _ResizeScreenCommand;
public ICommand ResizeScreenCommand
{
get
{
if (_ResizeScreenCommand == null)
{
_ResizeScreenCommand = new RelayCommand(
(argument1, argument2) =>
{
Grid grid = argument1 as Grid;
Window window = argument2 as Window;
if ((int)grid.GetValue(Grid.ColumnSpanProperty) == 2)
{
grid.SetValue(Grid.ColumnSpanProperty, 1);
window.WindowStyle = WindowStyle.None;
}
else
{
grid.SetValue(Grid.ColumnSpanProperty, 2);
window.WindowStyle = WindowStyle.SingleBorderWindow;
}
}
);
}
return _ResizeScreenCommand;
}
}
And the MultiValueConverter:
class CommandParamsConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
object[] parameters = values;
return parameters;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
My second attempt I followed the solution from How to Passing multiple parameters RelayCommand?
So, I've created within the ViewModel the new class, with two properties Grid and Window types and then tried to bind in xaml the Elements to these properties. But i this case the compiler complains that these properties are non-dependancy and cannot be bindded.
Please give me any hint how to solve it?
Below is the modified xaml code:
<Button Name="StretchScreenBtn" Content="Stretch screen" DataContext="{StaticResource CommandWindow}" Command="{Binding ResizeScreenCommand}"
Width="100" Height="50">
<Button.CommandParameter>
<vm:StretchingModel Grid="{Binding ElementName=ScreenGrid}" Win="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
</Button.CommandParameter>
</Button>
And the additionall class in the ViewModel:
class StretchingModel
{
public Grid Grid { get; set; }
public Window Win { get; set; }
}
Passing a Grid and a Window to a view model is not MVVM...a view model shouldn't have any dependencies upon any UI elements.
Anyway, to pass more than one value to the command you should combine your two approaches. The converter should return an instance of a StretchingModel:
class CommandParamsConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return new StretchingModel() { Grid = values[0], Window = values[1] };
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
...that the command accepts:
private ICommand _ResizeScreenCommand;
public ICommand ResizeScreenCommand
{
get
{
if (_ResizeScreenCommand == null)
{
_ResizeScreenCommand = new RelayCommand(
(argument) =>
{
StretchingModel model = argument as StretchingModel;
...
}
);
}
return _ResizeScreenCommand;
}
}

How to add contents of 2 fields to get summary in XAML code?

I would like to know how to get the column summary in XAML code. I'm able to get the row summaries using the code mentioned in attachment or image.
But I do not know how to add contents from "a1" ,"b1" and "c1" to get the "Summary" in XAML code only without using code-behind . I'm using Infragistics xamDataGrid
please refer this
You need MultiBinding and MultiValueConverter. Below example calculates sum of Num1 and Num2 properties and shows their Sum.
<DataGridTextColumn Header="Sum">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource SumCnvKey}">
<Binding Path="Num1"/>
<Binding Path="Num2"/>
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
Converter:
public class SumConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] != DependencyProperty.UnsetValue && values[1] != DependencyProperty.UnsetValue && values[2] != DependencyProperty.UnsetValue)
return ((int)values[0] + (int)values[1]).ToString();
else
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Binding custom Dependency Property to ListView width not updating

I have an IValueConverter named CategoryToGridViewConverter which has a DependencyProperty named ListViewWidthProperty. I have also inherited my converter from DependencyObject so that it will work with DependencyProperties. Here is how my converter is defined:
internal class CategoryToGridViewConverter : DependencyObject, IValueConverter
{
public static readonly DependencyProperty ListViewWidthProperty = DependencyProperty.Register("ListViewWidth", typeof (double),
typeof (CategoryToGridViewConverter), new PropertyMetadata(0d, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
Debug.WriteLine("ListViewWidth: " + dependencyPropertyChangedEventArgs.NewValue);
}
public double ListViewWidth {
get { return (double)GetValue(ListViewWidthProperty); }
set { SetValue(ListViewWidthProperty, value); }
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//Not relevant
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//Not relevant
}
}
}
Pretty simple. Then I am creating this converter in XAML (In ListView Resources section) like this:
<ListView Grid.Row="0" BorderThickness="0"
ItemsSource="{Binding SelectedCategory.Entries}"
x:Name="listView"
SizeChanged="ListView_OnSizeChanged">
<ListView.Resources>
<local:CategoryToGridViewConverter x:Key="CategoryToGridViewConverter" ListViewWidth="{Binding listView, Path=Width, Mode=OneWay}"/>
</ListView.Resources>
<ListView.View>
<Binding Path="SelectedCategory" Converter="{StaticResource CategoryToGridViewConverter}"/>
</ListView.View>
</ListView>
But the problem is that ListViewWidth never updates. It always stays at 0. But the ListView in question is obviously not having 0 width.
What am I doing wrong?
Edit: It also gives a binding error on output screen:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement
or FrameworkContentElement for target element.
BindingExpression:Path=Width; DataItem=null; target element is
'CategoryToGridViewConverter' (HashCode=33594544); target property is
'ListViewWidth' (type 'Double')
Does DependencyProperties only work for FrameworkElements? If so, how will my converter get to know about ListView's width?
I think you can just use a multi-value converter.
<local:CategoryToGridViewMultiConverter x:Key="CategoryToGridViewConverter" />
The converter:
public class CategoryToGridViewMultiConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var category = (Category)values[0]; // Assumption: you're using a class named Category
var listViewWidth = (double)values[1];
// same logic you had before
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Usage:
<ListView.View>
<MultiBinding Converter="{StaticResource CategoryToGridViewConverter}">
<Binding Path="SelectedCategory" />
<Binding ElementName="listView" Path="Width" Mode="OneWay" />
</MultiBinding>
</ListView.View>

Changing the appearance of collection of items according to a single property in XAML

I have 4 buttons in grid which datacontext is set to an object which has property that indicates what button should be enabled (it's enumerable).
Currenty I have done this in code-behind so that when that specific property changes, it disables all but one depending on the value. It works, but I really don't like to put stuff like this to code-behind. There must be a way to do this in xaml?
I could make own style for all four buttons and then do this with data triggers, but I would prefer more generic approach: use same style for all buttons that somehow applies differently depending on, for example, a button name and value of the property.
Thanks in advance.
You could use a MultiBinding to bind the IsEnabled property to a combination of the control's name and the property from your DataContext, and create a Style to apply it to all buttons in the Grid:
<Grid.Resources>
<local:EqualsConverter x:Key="EqualsConverter"/>
<Style TargetType="Button">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource EqualsConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Name"/>
<Binding Path="EnabledButtonName"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
And in code:
public class EqualsConverter
: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values.Length == 2 && object.Equals(values[0], values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
You can create an association between the enum you've created and the buttons by having integer references to your enum values and giving those enum values as ConverterParameters for corresponding buttons.
For Eg:
The enum:
public enum myOptions
{
value1 = 1,
value2 = 2,
value3 = 3,
value4 = 4
}
The Binding:
<Button IsEnabled = {Binding Path=myProperty,
Converter = {StaticResource EnumToBoolConverter},
ConverterParameter = 1} />
<Button IsEnabled = {Binding Path=myProperty,
Converter = {StaticResource EnumToBoolConverter},
ConverterParameter = 2} />
And the Converter:
public class EnumToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value == (int)parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}

Resources