I'm trying to use a Multibinding in combination with a converter with a Button control and Width property in XAML but I can't get it to work.
The converter is:
public class ColumnsToWidthConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return 40;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
It's hardcoded for 40 now, for testing purposes.
The XAML definition is:
<Button
Height="{Binding ElementName=root,Path=KeyHeight}"
FontSize="{Binding FontSize}"
Content="{Binding Display}"
Command="{Binding ElementName=root, Path=Command}"
CommandParameter="{Binding}"
Style="{StaticResource SelectedButton}">
<Button.Width>
<MultiBinding Converter="{StaticResource ColumnsToWidthConverter}">
<Binding Path="Columns"/>
<Binding Path="KeyHeight" ElementName="root"/>
</MultiBinding>
</Button.Width>
</Button>
The button is rendered from a ListView and defined in the ListView.ItemTemplate. When debugging the application, the converter is passed and the value of 40 is returned. The object[] values parameter contains the correct values passed in the MultiBinding paths. However, the width of the button is set to its content and not the 40 as in the example above.
The ColumnsToWidthConverter is defined in the parent ListView.Resources
<converter:ColumnsToWidthConverter x:Key="ColumnsToWidthConverter"/>
When I remove the MultiBinding and set the Width property to 40 in the XAML definition, the button is rendered correctly.
The root element is the usercontrol itself and KeyHeight is a DependencyProperty.
How do I set the button width using the multibinding?
The issue does not come from the multibinding but from the converter itself. When implementing a converter, you are expected to return the same type of value as expected by the control (there's no implicit conversion since you're the one implementing the converter). In this case, the Width property is a double, so you should return a value of the same type:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return 40d;
}
Related
I am trying to use the IValueConverter to calculate a new width for a TextBlock depending on the width on a Grid. But I always get this exception:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: 'Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.' Line number '264' and line position '76'.
I striped down the CalMeetingSize to everything but I still get the error. So I assume i making something wrong in the xaml? Can someone give me a hint?
<Grid x:Name="CalBackGround" Margin="163,30,0,0">
...
<TextBlock Height="18" Text="{Binding subject}"
Width="{Binding Path=Width,
ElementName=CalBackGround,
Converter={StaticResource CalMeetingSizeKey}}"
/>
...
<Window.Resources>
<local:CalMeetingSize x:Key="CalMeetingSizeKey"/>
</Window.Resources>
...
public class CalMeetingSize : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return 200;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Check whether you declared the Window.Resources before the first use in XAML so that it is known.
Also build you application once after adding the resource before using it helps sometimes fixing build-errors
You must also not bind to an element's Width, but always to its ActualWidth. Width is initialized to NaN and won't work here.
You need to bind to CalBackGround's ActualWidth property, not Width.
I am making an RPG in WPF and C#. I have movement buttons with images attached. I am trying to figure out how to change the image of the button depending on if there is a room available to move to in that direction. I have looked up converters but I am not quite sure how to implement them for my situation.
This is one example I have tried to implement that I found online:
<Button Content="{Binding MyBooleanValue, Converter={StaticResource
MyBooleanToImageConverter}}" />
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
bool v = (bool)value;
Uri path = new Uri((v ? "ImgSrcIfTrue.png" : "ImgSrcIfFalse.png"), UriKind.Relative);
return new Image()
{
Source = new System.Windows.Media.Imaging.BitmapImage(path),
Height = ...,
Width = ...,
};
}
Here is part of the code I am working on
<!-- Movement Buttons -->
<Button Grid.Row="1" Grid.Column="1"
Click="OnClick_MoveNorth">
<StackPanel>
<Image Source= "/Image/Buttons/Up.png"/>
</StackPanel>
</Button>
I already have functions for the boolean values, i am just trying to figure out how to implement a Converter to change the button image.
I have used the Boolean Visibility and hoping to do something similar.
Visibility="{Binding HasMonster, Converter={StaticResource BooleanToVisibility}}"
Better bind the Source property of an Image element in the Content of the Button:
<Button>
<Image Source="{Binding MyBooleanValue,
Converter={StaticResource MyBooleanToImageConverter}}"/>
</Button>
The converter would directly return a BitmapImage. If the image files are supposed to be assembly resources (i.e. they are part of your Visual Studio project and their Build Action is set to Resource), they must be loaded from Pack URIs:
public class BooleanToImageConverter : IValueConverter
{
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
var uri = (bool)value
? "pack://application:,,,/ImgSrcIfTrue.png"
: "pack://application:,,,/ImgSrcIfFalse.png";
return new BitmapImage(new Uri(uri));
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
You would add the converter to the Window's Resources like this:
<Window.Resources>
<local:BooleanToImageConverter x:Key="MyBooleanToImageConverter"/>
...
</Window.Resources>
I have label with a width of auto, that is bound to a property of type string.
<Label x:Name="ExampleLabel" Content="{Binding ExampleProperty}"Height="30" Width="Auto" >
I then have a property that is bound to the width of that label. The converter should convert the width to a negative value.
<UserControl.Resources>
<c:PositiveToNegativeConverter x:Key="PositiveToNegativeConverter"/>
</UserControl.Resources>
"{Binding ElementName=ExampleLabel, Path=Width, Converter={StaticResource PositiveToNegativeConverter}}"
I want the converter to execute when the label content changes, but it is only fired once, when the application loads.
Here is my converter
public class PositiveToNegativeConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (double)value * -1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Math.Abs((double) value);
}
}
Any help is much appreciated. Thanks.
Does it work if you bind to ActualWidth instead of Width? Width is just whatever value you last assigned to the Width property, while ActualWidth is a read-only live-updated runtime value for how wide the thing really is in the UI.
I would expect this to update when you want it to:
"{Binding ElementName=ExampleLabel, Path=ActualWidth, Converter={StaticResource PositiveToNegativeConverter}}"
I have a TextBlock like this:
<TextBlock Visibility="{Binding IsOnline, Converter={StaticResource boolToVisibilityConverter}}">
boolToVisibility returns Visible if IsOnline is true. But in a situation I want textblock be Collapsed if IsOnline is true.
I can make another converter which acts in reverse, but I want to know isn't it possible to do that in XAML with current converter?
You could potentially use a ConverterParameter value to determine whether to invert the output, for instance:
<TextBlock Visibility="{Binding IsOnline, ConverterParameter=true, Converter={StaticResource boolToVisibilityConverter}}" />
And in the converter itself:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool invertOuput = false;
if (parameter != null) {
bool.TryParse((string)parameter, out invertOuput)
}
// TODO: Converter logic
}
As far as I'm concerned, you'll have to make another converter, although, your converter (not reverese) already exists:
http://msdn.microsoft.com/pl-pl/library/system.windows.controls.booleantovisibilityconverter(v=vs.110).aspx
I have a Data Grid. Its Item source is set to a List. My problem is that Iam unable to apply string formatting . This is formats Ive tried . Am I missing some thing ?
StringFormat='MM/dd/yyyy'
StringFormat={0:dd-MMM-yyyy}
Attached the resultant grid
<sdk:DataGridTemplateColumn Header="Recieved Date" Width="Auto" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=RecievedDate, StringFormat=\{0:dd-MMM-yyyy\} }" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<sdk:DatePicker Name="dtpFinancialAndComplianceLog" Text="{Binding Path=RecievedDate,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
If I understand what you're trying to do correctly, you have a DataGrid column which you want to display a DateTime object in a certain format. Ordinarily a DateTime object will sort out its own formatting depending on the System.Threading.Thread.CurrentUICulture.
Easiest way I know of to force any object into a certain format is to use a custom IValueConverter:
namespace MyProject.Converters
{
public class FormatConverter : IValueConverter
{//Suitable only for read-only data
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return string.Empty;
if(string.IsNullOrEmpty(parameter.ToString()))
return value.ToString();
return string.Format(culture, parameter.ToString(), value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
After adding a namespace to your xaml: xmlns:conv="clr-namespace:MyProject.Converters" and declaring your converter in the control's resources <conv:FormatConverter x:Key="Formatter" />, you will need to bind your column's data using your new converter:
<TextBlock Text="{Binding Path=RecievedDate, Converter={StaticResource Formatter}, ConverterParameter=\{0:dd-MMM-yyy\} }" />