UI not updating using MVVM toolkit in WinUI 3 - c#

I am trying to change the size of a grid using data binding in order to be able to expand certain sections of my UI. I have looked online and nothing really seems to work. My window has a frame that loads a "root page" with another frame inside of it as seen in rootpage.xaml below. I have added a textbox but that does not seem to work. Interestingly enough, when I click the button present on the page. I do get a line outputted so my code is running. Adding a breakpoint shows similar results that the property FullScreenValue does in fact change. I think I am missing something in order to get the PropertyChanged event to be received or I may be unintentionally instancing multiple instances of my ViewModel. Looking for a solution.
My root page loaded into the frame in my window:
<Page
x:Class="MVVM.Views.rootPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MVVM.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ViewModels="using:MVVM.ViewModels"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.DataContext>
<ViewModels:RootPageViewModel x:Name="ViewModel"/>
</Page.DataContext>
<Grid x:Name="frameGrid" ColumnDefinitions="*, *" RowDefinitions ="*, *" Grid.Row="1" Margin="15, 0, 15, 0" >
<Frame x:Name="topleftFrame" Grid.Column="0" Grid.Row="0" CornerRadius="8" Margin="10, 10, 10, 10" Grid.ColumnSpan="{Binding FullScreenValue,Mode=OneWay}" Grid.RowSpan="{Binding FullScreenValue, Mode=OneWay}"/>
<AppBarButton Icon="FullScreen" Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,5,5,10" Command="{Binding FullScreenCommand, Mode=OneWay}"/>
Visibility="Visible"/>
<TextBlock Text="{Binding FullScreenValue, Mode=OneWay}" Grid.Row="1" Grid.Column="1"/>
</Grid>
</Page>
My ViewModel:
namespace MVVM.ViewModels
{
public partial class RootPageViewModel : ObservableObject
{
[ObservableProperty]
private int fullScreenValue;
public RootPageViewModel()
{
fullScreenValue = 1;
}
[ICommand]
void FullScreen()
{
fullScreenValue = 2;
Debug.WriteLine("HI");
}
}
}
As you can see I am trying to make use of the community toolkit. I have tried replacing some of these generated snippets with standard mvvm properties and commands to no avail. If I change the constructor to have a value of 2 I get my desired result, but can't seem to do it with this button! Send help.
My desired result is upon clicking the button, the frame will now span 2 columns and 2 rows instead of 1 column and 1 row. Maybe because this sort of UI concerns strictly the view it does not necessarily need a ViewModel but nonetheless I am still looking for help as I feel like I will run into this problem in the future. I am new to a lot of things in the Microsoft ecosystem so please forgive me if this is a repeat question and I just could not understand other answers.

Related

MvvmCross Wpf View with Sub View

I have a working program in Caliburn Micro but am moving over to MvvmCross. What I have working in Caliburn is a ShellView (Parent) that displays my navigation buttons and a cart. On that view, there is another view which is my selection of the navigation buttons, let's call it ActiveView (the view changes, in Caliburn it was ActiveItem() to change the view).
In MvvmCross, I cannot get this same functionality to work. After 3 days of searching and reading, I need help. Here is the image of the program, Blue outline is ShellView, inside of it Red outline is ActiveView.
What I get with MvvmCross is the ShellView, with no ActiveView. So the parent works, but no child is displayed. I have created a few other MvvmCross apps but they contain no navigation.
I have 2 Code Versions, First works but creates a second Window. Second keeps a single Window, but does not navigate. I need a single window with navigation. I feel I have a core misunderstanding and cannot find a source that explains it.
First Sample Works, but creates 2 Windows. An empty window (from MainWindow.xaml) and a second from ShellView. My assumption for 2 Windows opening when app is ran, is MainWindow being a window, and ShellView also being set to Window in xaml and cs.
Based on MvvmCross Playground.Wpf
<views:MvxWindow
x:Class="MvxKioskMtg.Wpf.Views.ShellView"
xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
xmlns:mvx="clr-namespace:MvvmCross.Platforms.Wpf.Binding;assembly=MvvmCross.Platforms.Wpf"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MvxKioskMtg.Wpf.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Background="#3d3d3d"
>
<views:MvxWindow.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Content="Welcome" Command="{Binding ShowWindowChildCommand1}" Grid.Column="0"/>
<Button Content="Checkout" Command="{Binding ShowWindowChildCommand2}" Grid.Column="1"/>
</Grid>
<ContentPresenter Content="{Binding}" Grid.Row="1" />
</Grid>
</DataTemplate>
</views:MvxWindow.ContentTemplate>
</views:MvxWindow>
ShellView.xaml.cs
public partial class ShellView : MvxWindow
{
public ShellView()
{
InitializeComponent();
}
}
Second Version Layout looks correct, but no navigation. Click buttons has no effect. Adding break point to the Command that changes views and it is never reached.
XAML changed from MvxWindow to MvxWpfView in 4 places, otherwise same as First Version.
<views:MvxWpfView
<views:MvxWpfView.ContentTemplate>
</views:MvxWpfView.ContentTemplate>
</views:MvxWpfView>
ShellView.xaml.cs
public partial class ShellView : MvxWpfView
{
public ShellView()
{
InitializeComponent();
}
}
In the XAML, if I update the DataContect to AncestorType={x:Type views:MvxWpfView} from Window, it does update the View, but the entire View. Not the ContentPresenter space. So I lose my navigation buttons.
Which of these methods is correct, and what am I doing incorrect? Am I totally off base? Thank you for any help and guidance you can provide. I'll happily read any sources.

Implement responsive Master/Detail in UWP using only one page

I would like to know if there's a way to implement a responsive Master/Detail page using only one. What I want is something exactly like the Project here:
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlMasterDetail
Except for the detail that instead of using two pages and navigating from one to another I would only use one page.
Is there a way to do it? If so, could you link me a working example?
Except for the detail that instead of using two pages and navigating from one to another I would only use one page.
After going through the project, I found it implemented a responsive master/detail experience based on the size of the screen. When the app view is sufficiently wide, the master list and detail view should appear side by side in the same app page. However, on smaller screen sizes, the two pieces of UI should appear on different pages, allowing the user to navigate between them. From my point of view, I think this is a good solution for implementing a responsive master/detail experience.
Is there a way to do it? If so, could you link me a working example?
The project already shows how to implement responsive Master/Detail in UWP using only one page, but it implements more and that makes it a little complex to understand. So I make a simple example which directly shows how to implement responsive Master/Detail in UWP using only one page.
Following is the main steps:
First, create a ListView to show master information in xaml page:
<!--Master VIEW-->
<ListView x:Name="ItemListView" Margin="0,0,0,8">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Left" Margin="10,8,0,0">
<TextBlock Text="{Binding Title}" FontSize="25" Width="400" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Second, specify the details view that shows the details item related to the selection on the master list in the same xaml page:
<!--DETAILS VIEW-->
<StackPanel Grid.Column="1" x:Name="ContentPanelDetail" Margin="10,0,0,0" DataContext="{Binding SelectedItem, ElementName=ItemListView}">
<TextBlock Text="{Binding Title}" MaxHeight="80" FontSize="30" HorizontalAlignment="Left" Margin="0" />
<TextBlock x:Name="DetailTextBlock" FontSize="35" Text="{Binding Content}" HorizontalAlignment="Left" Margin="0,18,40,0" Width="500" Height="Auto" TextWrapping="Wrap" />
</StackPanel>
Then, set the ItemsSource for the ListView in code behind:
public MainPage()
{
this.InitializeComponent();
//set the ItemsSource for the ListView
ItemDetails messageData = new ItemDetails();
ItemListView.ItemsSource = messageData.Collection;
ItemListView.SelectedIndex = 0;
}
Last but not least, put Master View and Details View into a SplitView and use VisualStateManager to make it more responsive.
Here is the simple example and the output for your reference.
To implement Master/Detail pattern on your page, you don't have to do it yourself. Instead you can use MasterDetailsView control from UWP Community Toolkit, it does a lot work for you + it is well documented.
Note: For details section of the control, do not set background to null (NoSelectionContent will be visible).

How to Prevent auto-resizing in a custom activity designer?

I hope you can help me with my problem. It's about a custom designer for a WF 4.0 activity, but the problem is essentially in the WPF of the designer.
Some background
I've created a custom WorkFlow activity to send e-mails. For the custom designer for the activity, I've previously been using regular Textboxes for the "Subject" and "Body" of the e-mail, but I'd like to use the ExpressionTextBox to easily bind it to the InArguments of the activity. The ExpressionTextBoxes are in a grid, and this grid is on a StackPanel.
I've set the the MinWidth, MaxWidth and Margin of the ExpressionTextBoxes to fit with the other controls, and in the Visual Studio Designer (viewing the custom activity designer, not the actual WorkFlow) everything looks as it should.
<sapv:ExpressionTextBox Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Right" Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}" OwnerActivity="{Binding Path=ModelItem}" VerticalAlignment="Center" MaxWidth="176" MinWidth="175" />
The problem
When used, initially it also looks as it should, but when the ExpressionTextBoxes are edited, they shrink into being really small. When text is entered, the control expands to fit the text, until it reaches its MaxWidth. When the editing ends, it goes back to it's MaxWidth. I'd prefer if it stayed the same size, regardless of being in edit-mode or not.
If you can't see it, open the image here
What I've tried
I've mostly been doing WinForms, and I'm pretty inexperienced with WPF, so I don't know if there are some funky properties or other settings that I've missed. I've tried setting width-properties of the parent controls (StackPanel and Grid), I've tried setting just the width (no min/max), but it seems to shrink regardless of what I set.
If you would like more information or code, please don't hesitate to ask.
Update
As you can see in the comments to Maurices answer, I figured out how to avoid the problem by removing the horizontalAlignment property, and then using margins to align it to the right. But I'm not going to mark an answer, until there's an explanation of why this behaviour happened in the first place. My XAML was almost identical to what Maurice posted, so there must be something wrong elsewhere.
The XAML for the ExpressionTextBox looks fine to me and when I try the following designer it works just fine.
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication2.MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Resources>
<sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
</sap:ActivityDesigner.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Label Content="Subject"
Grid.Row="2"
Grid.Column="0"/>
<sapv:ExpressionTextBox Grid.Column="1"
Grid.Row="2"
Height="Auto"
HorizontalAlignment="Right"
Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}"
OwnerActivity="{Binding Path=ModelItem}"
VerticalAlignment="Center"
MaxWidth="176"
MinWidth="175" />
</Grid>
</sap:ActivityDesigner>
So I suspect the problem is possibly in your grid definition.

c# WPF how to produce a flashy warning

I'm learning WPF, so bear with me.
I would like to have my WPF application flash in the user's face if a certain event is fired.
What is the best way to "notify" the user? I really want the user to react!
Cheers, Patrick
Environment: Windows7/64bit/.Net4
If you want the user to react you can force them to by simply opening a modal dialogue. The most lightweight of which being the MessageBox. You can also create normal modal windows using their ShowDialog method, you can make those windows as "fancy" as you want by getting rid of their normal appearance. This is achieved by setting the WindowStyle to None and AllowsTransparency to true, this will remove all the frame elements, so the window is now pure content.
Popups are handy for non-modal notifications and they already are content-only, but setting their AllowsTransparency to true may also be desired if you want rounded corners for example.
Best is entirely subjective and depends on many context variables but here is how I do it MVVM style.
In your main view model, define a property
pubic ObservableCollection<AlertViewModel"> Alerts { get; private set; }
in my case the AlertViewModel has only a "Message" property and a "Dismiss" RelayCommand.
In the XAML of your main view add
<Grid>
<all of my other other view controls>
<ItemsControl x:Name="AlertsControl" Opacity="50" ItemsSource="{Binding Alerts}"/>
</Grid>
Make sure it is the last item in the main container of your main view. This ensures it has the highest z order and will appear on top of all other controls.
Here is the data template for this view model
<DataTemplate DataType="{x:Type vm:AlertViewModel}">
<Border CornerRadius="10" Margin="3" Background="Red">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Margin="10" Grid.Column="0"
Command="{Binding ElementName=theWindow, Path=DataContext.DismissAlarmCommand}"
CommandParameter="{Binding}">Dismiss</Button>
<TextBlock Foreground="White" FontWeight="ExtraBold" Grid.Column="1"
Text="{Binding Message}" FontSize="20"
VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock>
</Grid>
</Border>
</DataTemplate>
Now,
Alerts.Add( new AlertViewModel() { Message = "Danger Will Robinson! Danger!" } );
Will pop a Bright red alert box onto the top of your main form. It does not go away until the user presses "Dismiss"
If you want it to flash or fade in and out or bounce up and down you can add animation in the data template.
You can use a Converter or data to Enable/Disable the rest of the controls in the app byt binding to AlertsControl.HasItems
Good luck.

Blend4, How to make WPF App(button show up pic)

How to make a button let a picture show up ?
what i Need to do, is creating 300 buttons each of these buttons will represent a unique path and pic every pic is defferent than the other? Unfortunately, WPF SketchFlow or Silverlight SketchFlow (I don't know the difference) can not be running as a program on computer. so what left is WFP app. Furthermore, i find it so difficult to just create one button linked to a pic's path!!!!.
I watched all of the Microsoft training Videos(the 5 days ones, if u dont know what i mean)http://www.microsoft.com/expression/resources/blendtraining/ . And still cant do it. I was searching for almost 4 weeks, and i still do.
Any idea how to create this essay app which require lots of work.
summery: 1-I don't know which app to use Silverlight or WPF app?(I don't know the difference)
2-i need to create a button that when i press on it, (New sorry) there will be a pic showing up in certain place that ill choose).
so in the end i need the code that will let the button work. direction for further info that ill need(websites that include vids or training by any type)
My regards SHeeDeED :)
Maybe you should start with a simple program: 1 button, showing 1 picture.
Handcraft it in XAML (no blend) and when you're stuck post a specific question here with the code.
I use Blend for most of my XAML/WPF UI design, and it works pretty well for me. I did, however, learn WPF and XAML by writing it longhand in the Visual Studio designer first. For any coding other than XAML (VB.NET, C#, C++, etc) I would highly suggest using Visual Studio as there are no bells and whistles in the Blend code window. It is essentially a colorful text editor.
As for buttons displaying images I have a couple of questions. I imagine your buttons are going to be loaded from a collection of some objects or something. By far, this is better than specifying each button in the XAML code.
I will assume your collection of objects has an ImagePath (or similarly named) property. The following should work out alright.
Load your ListBox with the Items, (see either http://www.WindowsClient.net for the old [Windows Forms] way, or read up on MVVM for the newer better way). Below is my listbox; ItemsSource is bound to the ImageCollection property on my ViewModel in this case. The items in my Imagecollection have an ImagePath property that is just a string file path to the image.
<ListBox ItemTemplate="{DynamicResource MyImageButton}" ItemsSource="{Binding ImageCollection}"/>
In Blend, you can create a DataTemplate by right clicking on the listBox, and going to Edit Additional Templates > Edit Generated Items (ItemTemplate).
From there you are just editing the layout of the items that will be created in the listbox. Below is my example of an item button with an image bound to the ImagePath property.
<DataTemplate x:Key="MyImageButton">
<Button Width="75">
<Button.Content>
<StackPanel>
<Image Source="{Binding ImagePath}" HorizontalAlignment="Left" Height="64" Width="64"/>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
Let me know if you need more info and I can post some more resource links.
EDIT
Alright, so here is a simple little application that I made to illustrate how this can be done probably the easiest as possible. In this application, I have 3 classes:
ImageButton - It just consists of two string properties, ImagePath and ImageName.
ImageButtonCollection - Inherited from ObservableCollection, creates and adds 300 buttons (iterates 1 to 300 and sets ImagePath to "C:\Images\image{i}.png" and ImageName to "image{i}".
The MainWindow class - I will post the contents below.
MainWindow.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ImageButtons"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="ImageButtonsCVS"/>
</Window.Resources>
<Grid>
<ListBox Height="311" HorizontalAlignment="Left" x:Name="ListBox1" VerticalAlignment="Top" Width="268" HorizontalContentAlignment="Stretch">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:ImageButton}">
<Border Background="#5A000000" CornerRadius="5">
<Grid Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.ColumnSpan="1" Height="30" Width="30" BorderBrush="#38FFFFFF" BorderThickness="1" Margin="5" Padding="0">
<Image Source="{Binding ImagePath}"/>
</Button>
<TextBlock Margin="0" TextWrapping="Wrap" Text="{Binding ImageName}" d:LayoutOverrides="Width, Height" Grid.Column="1" VerticalAlignment="Center" Foreground="White"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemsSource>
<Binding Source="{StaticResource ImageButtonsCVS}"/>
</ListBox.ItemsSource>
</ListBox>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="322,54,0,0" x:Name="Button1" VerticalAlignment="Top" Width="75" Click="CreateButtons" />
</Grid>
MainWindow.xaml.vb - I am more familiar with VB, but this can be easily ported to C# or whatever.
Class MainWindow
Private Sub CreateButtons(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim ImageButtonCVS As CollectionViewSource = Me.FindResource("ImageButtonsCVS")
ImageButtonCVS.Source = New ImageButtonCollection
End Sub
End Class
So, the ListBoxes ItemsSource property is bound to the CollectionViewSource created in the Window.Resources. The ListBox also has in it's resources a DataTemplate for the ImageButton class. Anytime an ImageButton is displayed in that listbox, that template will be used. The buttons click event is set to the CreateButtons method in the codebehind.
That method finds the CollectionViewSource resource, and sets it's source to a new instance of the ImageButtonCollection class. Once that is done, the UI is notified of an update (since the ObservableCollection has built in UI notification) and changes accordingly displaying 300 buttons with a little textblock next to them with the image name.
If you run this, create a folder on your C drive with some images named "imageX.png" with x being a number 1 to 300. Below are the other two classes so you can create/compile/run it.
ImageButton class
Public Class ImageButton
Public Property ImagePath As String
Public Property ImageName As String
Public Sub New()
End Sub
Public Sub New(ByVal Path As String, ByVal Name As String)
Me.ImagePath = Path
Me.ImageName = Name
End Sub
End Class
ImageButtonCollection class
Imports System.Collections.ObjectModel
Public Class ImageButtonCollection
Inherits ObservableCollection(Of ImageButton)
Public Sub New()
For i As Integer = 1 To 300
Me.Add(New ImageButton(String.Format("C:\Images\image{0}.png", i), String.Format("Image{0}", i)))
Next
End Sub
End Class
You never specified how you wanted the image displayed. You may not want them to be in a listbox. The beauty of WPF is that once you get it working in a listBox or whatever ItemsControl, you can easily change to another ItemsControl, or even customize one. Go into the ListBox template and change the ItemsHost to use a uniform grid or to stack items horizontally instead of vertically.

Categories

Resources