I digged out the internet in order to find a solution, and didn't found any clear solution and none of them working.
I'm looking for a specific solution, but if someone here have better solution it will be great..
In general, I'm trying to make controls that based on the Width and Height of the monitor.
- The easy way is put values that matches with my monitor and change them from CodeBehind.
Here's how it going:
- Create two variables in XAML (let's say the type is Double)
- Create third variables also in XAML. His value will be the difference of the
other two variables (in absolute)
- Create 3 control, the width of those controls is the value of the variables
<Window xmlns:sys="clr-namespace:System;assembly=mscorlib >
<sys:Double x:Key="size1">290</sys:Double>
<sys:Double x:Key="size2">450</sys:Double>
<sys:Double x:Key="size3"> Maybe something here? </sys:Double>
<StackPanel>
<Button Name="Button1" Width="{Binding Source={StaticResource size3}}"
Height="50" />
</StackPanel>
</Window>
I'm new in WPF, I do know C# pretty well but XAML is new for me (few months).
Basically I want to know if its possible to use undefined variables, such as 10% of the screen width.
Thanks.
You can use a Converter to achieve that.
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value / 10;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
in Xaml
<StackPanel>
<StackPanel.Resources>
<local:WidthConverter x:Key="WidthConverter" />
</StackPanel.Resources>
<Button Name="Button1"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth, Converter={StaticResource WidthConverter}}"
Height="50" />
</StackPanel>
Related
I have a weird error that the XAML designer displays when hovering over the text that gets the blue underline. It also refuses to show the components correctly in the preview. The text is simply
Object reference not set to an instance of an object.
That looks like a NullReferenceException, but I have no clue where it comes from. It displays correctly in the launched app.
It actually seems to be related to inheriting from List<string> AND exposing a settable property. If I remove either of that it works. But I want both for my converter.
To reproduce it, simply create an empty WPF .NET Framework project, and paste this below the MainWindow.xaml.cs code inside the namespace:
public class BuggyConverter : List<string>, IMultiValueConverter
{
public object Value { get; set; }
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
=> Visibility.Visible;
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) => null;
}
and this into the MainWindow.xaml:
<Window...>
<Window.Resources>
<local:BuggyConverter x:Key="conv" Value="{x:Static Brushes.Yellow}" />
</Window.Resources>
<Grid>
<Border Visibility="{MultiBinding Converter={StaticResource conv}}" />
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Visibility="{MultiBinding Converter={StaticResource conv}}" Width="100" Height="100" Background="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsSource>
<x:Array Type="{x:Type Brush}">
<SolidColorBrush Color="Green" />
<SolidColorBrush Color="Red" />
</x:Array>
</ItemsControl.ItemsSource>
</ItemsControl>
</Grid>
</Window>
Keep MainWindow.xaml open and then launch the app via the Start button. You can see a green and a red square. Since this is hardcoded in the XAML, I'd expect the designer to show just that.
Instead, when you exit the app, the designer shows the color hexcodes instead of the colored square, seemingly because it has problems with the converter setup.
What's the problem?
The code provided by you is working fine at my end. I think this code that you posted is only meant for StackOverflow and your actual code might be different. Anyway, My educated guess for the null reference exception is that, the public Object value{get; set;}
is getting null each time you try to convert something (in your actual use case scenario)
In case the code that you provided is exactly that you are using then just try to build your project to see if that null reference error
goes away or else try below steps
Empty your bin/debug folders from such project
Restart your IDE
Build your projects
I have the following property in my ViewModel
public IEquipment Equipment
{
get
{
return equipment;
}
set
{
if (equipment != value)
{
equipment = value;
InvokePropertyChanged("Equipment");
}
}
}
This item itself has a bool property, which is bound to an Ellipse in my View, which I want to use as a indicator item:
<Ellipse Width="10" Height="10" Fill="{Binding Equipment.IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
The BoolToColorConverter simply converts the color to either green (true) or red (false). During runtime Equipment can be an instance of one of two class types which inherit from IEquipment. Only one of them has the IsAvailable property. In practice this works fine, I get eighter my red or green color...or a gray one, in case the other type of equipment is active.
Problem is, that each time the GUI updates, the following warning gets output:
System.Windows.Data Warning: 40 : BindingExpression path error: 'IsAvailable' property not found on 'object'
How can I avoid this issue? Basically I want to bind to this property only if it is of the correct type.
I can think of two solutions, which I'm not particularly fond of:
Simply add the IsAvailable property to the other type and set it to null (BoolToColorConverter can handle null values and returns dark grey): This might be ok for a simple bool, but in my actual case there are other items, which are quite class specific.
Do the databinding in the code-behind: This might work. Using an event like Loaded on startup to set the binding manually at runtime based on the type. However, this might be troublesome for debugging later, because all other Bindings in the project happen directly in the xaml file. Additionally, Equipment might change during the lifetime of the ViewModel, so I would have to somehow track it.
Xaml doesn't bind to interfaces, it binds to concrete types.
If your types have different properties, then you need different xaml to bind them.
Use DataTemplates to specify different xaml for displaying each type.
If the properties on your derivatives of IEquipment (here Equipment and OtherEquipment as examples) differ a lot and do not share a common interface, they most likely differ in their appearance. In this case you would need different DataTemplates for each type. This is an example for a ContentControl, but it works the same fot ItemsContols with implicit data templates (no x:Key, but a DataType) that are applied automatically.
<ContentControl Content="{Binding Equipment}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Equipment}">
<Ellipse Width="10" Height="10" Fill="{Binding IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OtherEquipment}">
<Ellipse Width="10" Height="10" Fill="DarkGray" Margin="1"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
A workaround for your specific issue could be writing a custom, specialized value converter.
public class EquipmentAvailabilityToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Equipment equipment)
return equipment.IsAvailable ? Brushes.Green : Brushes.Red;
return (Brush)parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
<Ellipse Width="10" Height="10" Fill="{Binding Equipment, Converter={StaticResource EquipmentAvailabilityToColorConverter}, ConverterParameter={x:Static Brushes.DarkGray}}" Margin="1"/>
We're in the process of updating our gallery WPF application which contains our custom styled controls. The design is to have a toggle to show the XAML behind those custom controls, for easy reference and a guide for new colleagues.
The way I've currently implemented this is by creating two .xaml files, one containing just the controls, one with the controls and a textblock with the XAML coded used to implement those controls.
This is not something that's easily maintainable, since the quotes, >,< and other characters are not escaped in XAML strings. For reference this is what I have now in one of the 'Show code' views:
<TextBlock Visibility="Collapsed" Margin="5" Text="<controls:AutoCompleteTagBox
Name="AutoCompleteTagBoxWithStrings"
Margin="5"
ItemsSource="{Binding Names}"
FilterMode="Contains" />
<ListBox
ItemsSource="{Binding ElementName=AutoCompleteTagBoxWithStrings, Path=SelectedItems}"
Grid.Column="1"
BorderBrush="{StaticResource Blue}" BorderThickness="1" />"/>
As you can see, it doesn't look nice and once you update one of the controls you now have three places you need to change the XAML.
The next step is just to bind the TextBlock visibility and toggle it from 'Collapsed' to 'Visible'. But I want to know if there is a way to show the XAML in a textblock without having to hand write the string.
Thanks in advance for your advice!
Following from XAMIMAX's comment you could use an easy converter to save the xaml to a string using XamlWriter and strip the xmlns namespaces for brevity.
public class XamlConverter : IValueConverter
{
public readonly Regex xmlnsRegex = new Regex("xmlns=\".+\"");
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var source = value as FrameworkElement;
if (source != null)
{
//Save xaml and strip xmlns namespaces
var xaml = xmlnsRegex.Replace(System.Windows.Markup.XamlWriter.Save(source), "");
return xaml;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Example usage
<StackPanel>
<StackPanel.Resources>
<converters:XamlConverter x:Key="Converter_Xaml"/>
</StackPanel.Resources>
<Button x:Name="SourceButton" Content="Click Me" Margin="10"/>
<TextBlock Text="{Binding ElementName=SourceButton, Converter={StaticResource Converter_Xaml}}" TextWrapping="Wrap"/>
</StackPanel>
I want to resize content within a button so that when I "resize" my window, buttons also gets resized but size of content within button remains unchanged?
What should I do in order to make contents resized WRT button size.
Thanks, Faisal
PS: I am using GRID layout in WPF.
The easiest way that I can think of you doing that is for you to use a ViewBox element inside your Buttons:
<Button>
<ViewBox>
<!--Your Button content-->
</ViewBox>
</Button>
I believe the best approach to this issue would be to actually make a tiny converter which would be dynamically controlling the text size.
Here is an example of such a converter:
C#
using System.Globalization;
public class FontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double actualHeight = System.Convert.ToDouble(value);
int fontSize = (int)(actualHeight * .5);
return fontSize;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then here is the usage of this class within your xaml:
XAML
...
<Window.Resources>
<l:FontSizeConverter x:Key="FSConverter" />
</Window.Resources>
...
<Grid>
<Button Content="Dat Button" FontSize="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}, Converter={StaticResource FSConverter}}"/>
</Grid>
Hope this helps, let me know if you will have any issues with that.
K.
I have this code in WPF
Every new form gets added by clicking on "Add New" to the Itemscontrol.
Event is a CSLA call.
<Menu Grid.Row="0">
<MenuItem Header="Add New"
csla:InvokeMethod.MethodName="AddNew"
csla:InvokeMethod.TriggerEvent="Click" />
</Menu></ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<DataTemplate.Resources>
<FrameworkElement x:Key="ReqProxyElement" DataContext="{Binding}" />
</DataTemplate.Resources>
<Grid>
<ContentControl Visibility="Collapsed" Content="{StaticResource ReqProxyElement}" />
<Grid>
<Grid.DataContext>
<formviewmodels:ReqViewModel Model="{Binding Source={StaticResource ReqProxyElement}, Path=DataContext}" />
</Grid.DataContext>
<formviews:ReqView />
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now inside the form ReqView, I have converter call for radio button.
<Label Grid.Row="10" Grid.Column="0" Content="required" />
<StackPanel Orientation="Horizontal" Grid.Row="10" Grid.Column="1" >
<!--<RadioButton Content="Yes" GroupName="Required" IsChecked="{Binding Model.Required, Converter={StaticResource NullableBooleanToFalseConverter}}"></RadioButton>
<RadioButton Content="No" GroupName="Required" IsChecked="{Binding Model.Required, Converter={StaticResource ReverseBoolean}}"></RadioButton>-->
<RadioButton Content="Yes" GroupName="GRequired" ></RadioButton>
<RadioButton Content="No" GroupName="GRequired" ></RadioButton>
</StackPanel>
In this scenario when I click on add New , the ItemsControl as is the nature of the beast tries to bind back to the Form and goes into an infinite loop in the converter call.
The converter code is given below.
public class ReverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
{
return (!((bool)value));
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
{
return (!((bool)value));
}
return value;
}
}
public class NullableBooleanToFalseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return false;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Can any one come up with a solution where the convereter don't kick the code into infinite loop.
What happens is when a Add New is clicked, if there is already a form in the Itemscontrol, it tries to bind back to the form again before creating a new empty form.
The binding back sets the radio button true say if true is selected but then setting it to trus starts a tennis match between the two converters one converts it the other converts it back and the model says No way the value is true and so on it goes until application hits stackoverflow...
Interesting situation I have hit into with WPF and MVVM pattern.I am looking for a solution without breaking the MVVM paradigm. If converters can be done away with that will work too.
The backend calls are CSLA reistered properties.
Thanks
Dhiren
You can bind only the Yes radio. Since it's IsChecked property is bound to your bool, the bool would turn to false when you check the other radio. You don't even need the ReverseConverter here.
UPDATE:
Only bind the Yes radio to your field. RadioButton are mutually exclusive when they are in the same group (which they are). When you select one, you change the other. If you select the No radio, yes would be unchecked, and so Required would be false.
As for the initial values, if you set No to false, it would be selected. And since Yes is bound to Required, it'll save your value. Do something like this:
<RadioButton Content="Yes" GroupName="GRequired" IsChecked="{Binding Required}"/>
<RadioButton Content="No" GroupName="GRequired" IsChecked="False"/>
UPDATE II:
The binding mechanism in WPF ties two values together, so when one changes the other does too, and it can work both ways. RadioButton.IsCheck is just a bool property, so when it's value change it changes the value it's bound to (in this case Required). When you check No, you also uncheck Yes, it's IsChecked property changes. and that changes Required.
For more on Data binding see: http://msdn.microsoft.com/en-us/library/ms752347.aspx.
So, you see, you don't need the ReverseConverter, because you don't need to bind No to anything. As a matter of fact, you don't even need NullBooleanConverter, since WPF already knows how to convert bool? to bool.
Regards,
Yoni