I am working on internationalizing a WPF application. I am stuck at a situation where a ToolTip to be set near a border control which is to be concatenated like this:
RoleType : Manager
I am binding RoleType in ViewModel which has Manager, TechLead, Engineer etc. RoleType string is fixed and is translated in Resources file. Now in view, I need to concatenate and show the user who has logged in.
I tried MultiBinding but after login, my screen turns blackout. I cannot exit my application.
Here is the code I am trying:
<StackPanel Grid.Row="0" Orientation="Vertical" VerticalAlignment="Top">
<Border BorderBrush="{Binding BorderBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="auto" Width="auto"
Background="Transparent" >
<Border.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} : {1}">
<Binding Path="Text" ElementName="{languageTranslation:Translate RoleType}" />
<Binding Path="Text" ElementName="{languageTranslation:Translate {Binding UserName}}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Border.ToolTip>
<ContentControl Height="65" VerticalContentAlignment="Top" HorizontalAlignment="Center" ContentTemplate="{StaticResource UserProfileIcon}"></ContentControl>
</Border>
What am I doing wrong? Converters are not required as it is only strings.
Related
I have a weird issue.
In my application (witten with C# .net framework 4.8 with Microsoft's MVVM toolkit) I have a ListView bound to a BindingList<VisualMachine>, everything works as expected.
Now I wanted to add to the Itemtemplate a DockPanel with data from another BindingList<PreviewParameter> (another property of the original VisualMachine object ).
This is when weirdness starts: In this new ItemTemplate I have a Grid that contains an Image, a TextBlock and a Tooltip. The TextBlock and the Tooltip are bound to the same object, but only the ToolTip actually show data!
I feel like it's some DataContext Issue, but I am not able to pin it... Can anybody give me some advice?
Thanks!
The code:
<ListView Name="MachinesListView" Margin="2" HorizontalContentAlignment="Stretch" BorderThickness="0" DockPanel.Dock="Top" ItemsSource="{Binding Path=Machines}" PreviewMouseRightButtonDown="ListView_PreviewMouseRightButtonDown" SelectedItem="{Binding Path=SelectedMachine}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- Other stuff -->
<DockPanel>
<!--#region PREVIEW PARAMETERS PANEL-->
<WrapPanel HorizontalAlignment="Stretch" DockPanel.Dock="Bottom" Visibility="{Binding Path=PreviewParameters.Count, Converter={StaticResource CountToVisConverter}}">
<ListView ItemsSource="{Binding Path=PreviewParameters}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid MinWidth="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto" MinWidth="25"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Path=Icon, Converter={StaticResource ResourceKey=BmpToBmpImageConverter}}"/>
<TextBlock Grid.Column="1" MaxWidth="100" DataContext="{Binding}">
<TextBlock.Text>
<!-- THIS DOES NOT APPEAR -->
<MultiBinding StringFormat="{}{0} [{1}]}">
<Binding Path="Parameter.VisualizedValue"/>
<Binding Converter="{StaticResource ParamToEnumDescConverter}" Path="Parameter"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Grid.ToolTip>
<TextBlock MaxWidth="100" TextWrapping="Wrap">
<TextBlock.Text>
<!-- THIS DOES APPEAR -->
<MultiBinding StringFormat="{}{0} [{1}] - {2} TEST:{3} {4}">
<Binding Path="Parameter.Reference"/>
<Binding Path="Parameter.SetupIndex"/>
<Binding Path="Description"/>
<Binding Path="Parameter.VisualizedValue"/>
<Binding Converter="{StaticResource ParamToEnumDescConverter}" Path="Parameter"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid.ToolTip>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</WrapPanel>
<!-- Other stuff -->
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What happens:
I found it.
There was a } in the StringFormat property of the TextBlock's MultiBinding.
So instead of
<MultiBinding StringFormat="{}{0} [{1}]}">
it should be
<MultiBinding StringFormat="{}{0} [{1}]">
And BAM! Now it works.
I'll leave the question as the following reminder to anybody: "Write your code, review it, than go take a coffee o chat a little and then come back. You'll be amazed on how blind you could be."
There is an icon that I want to always be visible, but I want the tooltip to be conditionally visible. Here is the code that I currently have:
<TextBlock Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
FontSize="15"
Visibility="{Binding IsConnected, Converter={StaticResource BooleanToVisibilityConverter}}">
<fa:ImageAwesome Icon="{Binding Path=BatteryLevelIcon, UpdateSourceTrigger=PropertyChanged}"
Height="20"
Width="20"
Foreground="Green"
Visibility="{Binding IsConnected, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ToolTipService.ToolTip>
<TextBlock Visibility="{Binding IsCharging, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}%">
<Binding Path="BatteryPercentage" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTipService.ToolTip>
</TextBlock>
So, I want the tooltip to only show up when IsCharging is false. The issue that I am having is that because the Visibility property is on the tooltip textblock instead of the tooltip itself, setting it to not visible only gives me a empty tooltip, instead of the tooltip not appearing at all. I have tried defining the content of the tooltip (textblock) in UserControls.Resources and then setting the textblock and IsEnabled, but it gave me the error:
a value of type tooltipservice cannot be added to a collection or dictionary of type inlinecolection
It doesn't seem there is an easy way to set the visibility for the tooltip. If anyone has any suggestions it would be greatly appreciated!
You could use ToolTipService.IsEnabled property for the purpose
ToolTipService.IsEnabled="{Binding IsToolTipVisible}"
Where IsToolTipVisible Where is the View Model property which dictates where to enable the tooltip
Complete Code
<TextBlock Grid.Row="2" ToolTipService.IsEnabled="{Binding IsToolTipVisible}"
Grid.Column="0"
VerticalAlignment="Center"
FontSize="15"
Visibility="{Binding IsConnected, Converter={StaticResource BooleanToVisibilityConverter}}">
<fa:ImageAwesome Icon="{Binding Path=BatteryLevelIcon, UpdateSourceTrigger=PropertyChanged}"
Height="20"
Width="20"
Foreground="Green"
Visibility="{Binding IsConnected, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ToolTipService.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}%">
<Binding Path="BatteryPercentage" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTipService.ToolTip>
</TextBlock>
I have a strange behaviour using ObjectDataProvider. I need to bind a TextBlock with ToString method but, when I enter in method my properties are wrong.
This is my simple ObjectDataProvider:
<Window.Resources>
<ObjectDataProvider x:Key="ToString" MethodName="ToString" ObjectType="{x:Type entities:Season}" />
</Window.Resources>
And this is my ListView:
<ListView Grid.Row="2" Name="lvSeasons" HorizontalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Source={StaticResource ToString}}" VerticalAlignment="Center" />
<Button Grid.Column="1" VerticalAlignment="Center" Background="Transparent" BorderBrush="Transparent" Click="btDeleteSeason_Click">
<TextBlock FontFamily="{StaticResource FontAwesome}" Text="" FontSize="20" Foreground="Red" HorizontalAlignment="Center" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My method simply concat two properties:
public override string ToString()
{
return StartYear + "/" + EndYear;
}
In debug I can see that start and end year are always 0. If I bind my TextBlock using {Binding StartYear} it's correct and value is 2019.
Where can the problem be?
You do not need an ObjectDataProvider. Just write
<TextBlock Text="{Binding}" ... />
WPF will call the ToString method by default.
You do not even need to override ToString when you use a MultiBinding with an appropriate StringFormat:
<TextBlock ...>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}/{1}">
<Binding Path="StartYear "/>
<Binding Path="EndYear "/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
I have many user controls and i have main window which contains a content control and list box when user select from list box i bound the selected user control to the content control the problem is when the user control bound for the first time the validation rules is appears but when user control bound for the second time the validation rules disappear what is the problem ?
here is the main window :
<Grid>
<ListBox x:Name="FormsListBox" Margin="0,5,0,5" Grid.Row="1" Grid.Column="0" Width="180" ItemsSource="{Binding Formlist}" SelectedItem="{Binding SelectedFormInfo}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Resources/Capture.PNG" ></Image>
<TextBlock Text="{Binding Path=FormName}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Row="1" Grid.Column="1" x:Name="MainStackPanel" >
<ContentControl Content="{Binding Path=SelectedFormInfo.MainForm}">
</ContentControl>
</StackPanel>
</Grid>
here is the sample of validation role in user control:
<StackPanel Width="315" Margin="20,0,10,0">
<TextBox x:Name="TxtWeaponNumber" Width="315">
<TextBox.Text>
<Binding Path="SelectedWeapon.weaponNumber" Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged" ValidatesOnNotifyDataErrors="True"
ValidatesOnDataErrors="True" NotifyOnValidationError="True"
NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True">
<Binding.ValidationRules>
<validationRules:RequiredRule ValidatesOnTargetUpdated="True" ValidationStep="RawProposedValue" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
Note: MainForm in SelectedFormInfo contains thee selected user control
i set my user control in AdornerDecorator and the Validation did not disappear
I have several groups of Observable collections of items that are updated on a background thread at a regular interval (30 to 60 seconds). These collections are displayed through ItemsControls on the View. The parent and the items within the control have several display attributes tied to the status of each item.
Status will determine what shape will be displayed next to the text as well as the stroke and fill color of that shape.
Status will determine the background color and text color of the text for that item.
Status will determine if a countdown timer is displayed in the item (Timer has no tie back to the viewmodel)
Status may determine the border color of the parent container.
I am currently performing this logic in individual IValueConverters for each property. It works but it feels cumbersome and spread out. I almost want to somehow subscribe to the PropertyChanged Event in the UI and have it call a single method to render all the display for that item so that all the logic is contained in a single place. Is there a better way to do this or should I just stick to IValueConverters?
Here is an example of what I have.
The collection:
public ObservableCollection<PanelItem> PanelItems1
{
get { return panelItems1; }
set
{
panelItems1 = value;
base.OnPropertyChanged("PanelItems1");
}
}
PanelItem is a small collection of properties that include: Name, Value (Status), Description. The ItemsControls is similar to the following:
<Border Grid.Row="0" Grid.Column="0"
BorderBrush="{Binding Path=PanelGroup1.HighestStatus, Converter={StaticResource ParentBorderColorConverter}}"
BorderThickness="3" Height="Auto" Width="Auto" Margin="0,0,2,0">
<StackPanel Grid.Column="0" Grid.Row="0">
<Label Grid.Row="0" Grid.Column="0" Content="First Group" Style="{StaticResource panelTitle}" />
<ItemsControl ItemsSource="{Binding Path=PanelItems1, Mode=TwoWay}"
ItemTemplate="{StaticResource PanelItemTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!-- Here is the Data Template -->
<DataTemplate x:Key="PanelItemTemplate">
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand">
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2">
<Path.Data>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeConverter}" />
</Path.Data>
<Path.Fill>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeColorConverter}" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Status" Mode="OneWay" Converter="{StaticResource ShapeBorderConverter}" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>
</DataTemplate>
</StackPanel>
</Border>
Why don't you just declare a normal class that implements the INotifyPropertyChanged interface for your Status object? Just add the required properties into it, such as Geometry, Fill and Stroke, etc... if you did that, you wouldn't need any Converter classes and you could do something like this:
<DataTemplate x:Key="PanelItemTemplate">
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand" >
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2" >
<Path.Data>
<Binding Path="Status.Geometry" Mode="OneWay" />
</Path.Data>
<Path.Fill>
<Binding Path="Status.Fill" Mode="OneWay" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Status.Stroke" Mode="OneWay" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>
</DataTemplate>
It's possible to create just one converter which will include all the conversion logic and return a new class which you will bind to:
public class MyNewConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Perform all required conversions here and return them as a new type of object
return new
{
Data = ...,
Fill = ...,
Stroke = ...
};
}
}
Then all you need to do is modify your Path's DataContext property to use this converter.
<Viewbox MaxHeight="20" HorizontalAlignment="Left" Cursor="Hand">
<WrapPanel>
<Path Margin="2,2,2,2" StrokeThickness="2" DataContext="{Binding Path=Status, Converter={StaticResource MyNewConverter}}">
<Path.Data>
<Binding Path="Data" Mode="OneWay" />
</Path.Data>
<Path.Fill>
<Binding Path="Fill" Mode="OneWay" />
</Path.Fill>
<Path.Stroke>
<Binding Path="Stroke" Mode="OneWay" />
</Path.Stroke>
</Path>
<ContentPresenter Content="{Binding Path=Name}" Margin="5,0,0,0" />
</WrapPanel>
</Viewbox>