Change Border Thickness on Mouse Over UWP - mvvm

I am designing menu and I have list of items in VariableSizedWrapGrid as shown in figure.
I want to change border thickness of Current active element on MouseOver also I want to change foreground color of title 'Business'.
How should I achieve this in UWP using MVVM?
Way I know is:
Use Interaction and call ViewModel command on MoseOver.
Command will set BorderWidth property of VIewModel
BorderWidth property would bind to BorderThickness property of control
BorderThickness="{Binding BorderWidth}"
This will work great with one VariableSizedWrapGrid's item. But I have 3 items as shown above. Do I need to create 3 commands with 3 ViewModel Properties which will bind border thickness to respective item?

Unless if you have a real reason to set the BorderWidth from inside your viewmodel (e.g. calculated width depending on other properties of your viewmodel/model, you can simply edit the default GridViewItem style and use the VisualStateManager to handle the PointerOver event.
You can find the default styles on your disk, with a file per SDK version.
C:\Program Files (x86)\Windows
Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.10240.0\Generic\generic.xaml
C:\Program Files (x86)\Windows
Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.10586.0\Generic\generic.xaml
Or you can also find them on MSDN, like the one for GridViewItem. You can also edit the existing style in Blend.
You'll end with a custom style with a name (x:Key) that you can use on your VariableSizedGrid's GridViewItem. The part in the style that you have to edit is in the PointerOver visual state:
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderRectangle"
Storyboard.TargetProperty="Opacity"
Duration="0"
To="1"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderRectangle" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualBlack" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
</Storyboard>
</VisualState>
As you can see, the state already changes the Opacity and Stroke, just add another DoubleAnimation for the BorderThickness properties. Other states will use the default.

Related

Multi-level bullet list in .NET MAUI

I need to create a multi-level bullet list in my .NET MAUI app which is at least 2 levels, possibly 3, even 4 levels deep.
How do I handle this in XAML or do I need to handle it in Blazor?
If I understand correctly, you could use a Grid. ColumnDefinitions property could be used to set different level while RowDefinitions could be used to set items. You could use either Absolute or Star value to set the width or height.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
For more info, you could refer to .NET MAUI Grid.

Pass the VisualState of CollectionView Item VisualElement to its child VisualElements

I am having the following situation:
CollectionView, each item is Border, that contains other controls.
When selected, the VisualState of the Border changes to selected. The child controls however do not have a change in their state.
Is there an easy way to link/pass those VisualStates to all child controls?
(cascade, 2,3,4 and more levels deeper)
Edit: I know how to use Triggers, Setters in Styles and other approaches to change the UI of the application. The question is specifically for changing the VisualState of the nested VisualElements. Cannot find anything anywhere on this matter.
You can try to set state on multiple elements.
Visual states could be attached to and operated on single elements. And it's also possible to create visual states that are attached to a single element, but that set properties on other elements within the same scope. This avoids having to repeat visual states on each element the states operate on.
The following example shows how to set state on multiple objects, from a single visual state group:
<StackLayout>
<Label Text="What is the capital of France?" />
<Entry x:Name="entry"
Placeholder="Enter answer" />
<Button Text="Reveal answer">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
<Setter TargetName="entry"
Property="Entry.Text"
Value="Paris" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
Note: Property paths are unsupported in Setter elements that specify the TargetName property.
You can also try to define custom visual states, for more information, you can check: Define custom visual states .

Change ImageButton source based on Theme in xaml

I want to change the Source of an ImageButton in xaml based on the Theme (i.e. Light vs Dark). I get a System.NullReferenceException 'Object reference not set to an instance of an object.' when I use the following:
<ImageButton
Grid.Row="1"
Margin="10"
Command="{Binding CreateCommand}"
Source="{AppThemeBinding Light=add_box_black_48dp.svg, Dark=add_box_light_48dp.svg}"
HorizontalOptions="End"
VerticalOptions="End"/>
If I change the Source to the following everything works
Source="add_box_white_48dp"
Can I use AppThemeBinding to change the ImageButton Source in this way?
<Edited on 6/4/2022 to show xaml for cases that work and those that do not work. Also changed the names of the svg files to reflect light and dark cases>
I am using Visual Studio Community 2022 (64-bit) - Preview
Version 17.3.0 Preview 1.1
This ImageButton xaml throws the exception:
<ImageButton
Margin="10"
Command="{Binding CreateNewAccountCommand}"
Source="{AppThemeBinding Light=add_light.svg, Dark=add_dark.svg}"
HorizontalOptions="End"
VerticalOptions="End"
BackgroundColor="#376489"
CornerRadius="8"
WidthRequest="36"
HeightRequest="36">
</ImageButton>
This ImageButton xaml works and does not throw an exception
<ImageButton
Margin="10"
Command="{Binding CreateNewAccountCommand}"
Source="add_light.svg"
HorizontalOptions="End"
VerticalOptions="End"
BackgroundColor="#abdbe3"
CornerRadius="8"
WidthRequest="36"
HeightRequest="36">
</ImageButton>
This also works and does not throw an exception
<ImageButton
Margin="10"
Command="{Binding CreateNewAccountCommand}"
Source="add_dark.svg"
HorizontalOptions="End"
VerticalOptions="End"
BackgroundColor="#376489"
CornerRadius="8"
WidthRequest="36"
HeightRequest="36">
</ImageButton>
To work cross-platform, refer to .png files. These get built automatically by Maui:
Each image resource needs Property/BuildAction: "MauiImage".
Refer to .png in xaml:
Source="{AppThemeBinding Light=add_box_black_48dp.png, Dark=add_box_light_48dp.png}"
Verified by modifying Maui project's default MainPage, to say:
<Image Source="{AppThemeBinding Light=dotnet_bot.png, Dark=dotnet_bot.png}" ... />
This refers to a Media item dotnet_bot.svg, which (I infer) gets converted by "MauiImage" into a .png resource.
NOTE: Maybe the plan is to be able to leave off the extension. This works on Android, but the image does not show on Windows:
<!-- Doesn't work currently on Windows -->
<Image Source="{AppThemeBinding Light=dotnet_bot, Dark=dotnet_bot}" ... />

Hiding parts of OpenXml documents programmatically

Is it possible to programmatically hide parts of an OpenXML document, without actually removing it?
The reason I would want to do this: This is a template file, dynamic parts are filled using databindig. And some parts should be hidden, if there is no backing data. But don't want to actually remove parts from the document, so the document could be "refreshed" later with new data.
Something like display: none in html/css.
The is no exact equivalent to hiding content in Word using the open xml sdk. However there are two approaches that might work for you:
Hidden paragraph trick
Create a style, let's call it HiddenParagraph. Define it in your styles.xml as follows:
<w:style w:type="paragraph" w:customStyle="1" w:styleId="HiddenParagraph">
<w:name w:val="HiddenParagraph" />
<w:next w:val="Normal" />
<w:pPr>
<w:spacing w:line="14" w:lineRule="auto" />
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorEastAsia" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi" />
<w:sz w:val="22" />
<w:szCs w:val="22" />
</w:rPr>
</w:style>
The w:line=14 makes the paragraph effectively invisible.
Now render the content your don't want to see using this paragraph style.
<w:p>
<w:pPr>
<w:pStyle w:val="HiddenParagraph" />
</w:pPr>
<w:r>
<w:text>you should not be able to see me
</w:r>
</w:p>
To show the content again just change the paragraph style to normal or some other more sane style.
Custom XML Part
Store data you don't want to display in the document in a custom xml data store, although this might not work in your specific scenario
Reference
http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2010/10/27/59361.aspx

Problem Binding Commands to TreeViewItem using MVVMLight

I'm trying to use MVVMLight to bind a TreeViewItem Selected event to a command.
The TreeViewItem's are defined in a HierarchicalDataTemplate so I cannot add Interaction.Triggers (as shown below)
<HierarchicalDataTemplate
x:Key="TreeViewItemTemplate"
ItemsSource="{Binding ChildReportViewModels}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Selected">
<MvvmLight_Command:EventToCommand Command="{Binding LoadReportCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</HierarchicalDataTemplate>
How else can I add the EventTrigger to each TreeViewItem?
Thanks.
I forgot about this question.
For future ref, here's the solution I used...
Instead of trying to bind the EventToCommand to the Selected event of the TreeView,
I bound it to the MouseLeftButtonUpEvent of the TextBlock declared in the HierarchicalDataTemplate for TreeViewItems.
<HierarchicalDataTemplate
x:Key="TreeViewItemTemplate"
ItemsSource="{Binding ChildReportViewModels}"
ItemContainerStyle="{StaticResource TreeViewItemContainerStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<gs_cmd:EventToCommand Command="{Binding LoadPublicationCommand, Mode=OneWay}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
I have not much knowledge about MVVMLight and especially about EventTrigger.
But since there is no answer to your qestion yet the codeplex article TreeViewWithViewModel might help. It shows how to bind to SelectedItem and IsExpanded Properties in a wpf-treeview and how these can be used to implement load on demand in the treeview.