Silverlight DataForm+ChildWindows+MVVM: ComboBox's DataField dont get populated - mvvm

i have my View Page with a GridView control. Items in the Grid are edited using a popup Childwindows with the following xaml:
<toolkit:DataForm.EditTemplate>
<DataTemplate>
<StackPanel>
<toolkit:DataField Label="Avisar a: ">
<ComboBox ItemsSource="{Binding Path=Sucursales}"/>
</toolkit:DataField>
<toolkit:DataField Label="Mensaje:">
<TextBox Text="{Binding mensaje, Mode=TwoWay}"/>
</toolkit:DataField>
<toolkit:DataField Label="Estado: ">
<ComboBox ItemsSource="{Binding Path=EstadosMensaje}"/>
</toolkit:DataField>
</StackPanel>
</DataTemplate>
</toolkit:DataForm.EditTemplate>
</toolkit:DataForm>
DataContext to this popup is injected view constructor from the parent view as follow:
AlertaForm frm = new AlertaForm(DataContext as AlertasViewModel);
frm.Show();
//ChildWindows constructor
public AlertaForm(AlertasViewModel viewModel){
InitializeComponent();
DataContext = viewModel;
}
As you can see, ChildWindows and parent view share the same ViewModel.
The problem is that ComboBox controls dont get populated. TextBox field are binded correctly,they display values from DataContext property, that is confusing because that prove that the DataForm recognize the ViewModel passed to the ChildWindows AlertaForm.
Obviously i'm missing something here but cannot figure out what is.
Thanks

I end up throwing away the User control with the DataForm together
sticking in ChildWindows with common controls. It seems that DataForm is not sweet to
complex scenarios

Related

How to pass objects to PopupPage using MAUI.Toolkit or Mopup plugins?

I have a Maui app where I use MVVM pattern with MAUI Toolkik and also trying with Mopup plugin but I haven't found how to pass objects to Popup pages combined with MVVM. At the moment, I have a page, which I use to navigate to the PopupPage successfully and also I am able to connect the PopupPage with its viewmodel. What I am unable to do is to pass any kind of object to the PopupPage.
I have tried to set the PopupPage constructor with parameters but the methods to navigate to the PopupPage only recognize parameters setted on the code behind.
Here is my code:
Popup
<mopup:PopupPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NewScholarApp.Views.MessagePopup"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:mopup="clr-namespace:Mopups.Pages;assembly=Mopups"
xmlns:viewmodels="clr-namespace:NewScholarApp.ViewModels"
x:DataType="viewmodels:MessagePopupViewModel">
<mopup:PopupPage.BindingContext>
<viewmodels:MessagePopupViewModel/>
</mopup:PopupPage.BindingContext>
<VerticalStackLayout BackgroundColor="White" HorizontalOptions="Center" VerticalOptions="Center" HeightRequest="100" WidthRequest="100">
<Label
Text="{Binding Message}"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</mopup:PopupPage>
I use this to navigate from my page viewmodel
await _popupNavigation.PushAsync(new MessagePopup(string text = "tex"));
If I try to set a parameter, shows this error, even that in my PopupPage constructor I have setted a parameter
"MessagePopup does not contain a a constructor that contains 1 argument"
**MessagePopupViewModel **
public partial class MessagePopupViewModel : ObservableObject
{
#region AnP
[ObservableProperty]
private string message;
private readonly IApiService _apiService;
#endregion
public MessagePopupViewModel(string tex)
{
Message = tex;
}
}
you are navigating using this code
await _popupNavigation.PushAsync(new MessagePopup(string text = "tex"));
so MessagePopup MUST have a constructor that accepts a parameter
public MessagePopup(string somevalue)
if you also want to pass that value to your VM, then you can add
BindingContext = new MessagePopupViewModel(somevalue);
if you do this, then you should remove the BindingContext property from the XAML

How to make a multi-steps registration page with multi ContentView?

In the app I'm working on, there's a multi-steps registration, 4 steps:
to accomplish it, I'm thinking to have a single page to host a content view of the registration step, when it passes the validation requirements I remove it and inject the next content view.
This is an example to simplify my need:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamApp"
x:Class="XamApp.MainPage">
<local:Register1/>
</ContentPage>
and the Register1 looks like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamApp"
x:Class="XamApp.Register1">
<ContentView.Resources>
<ResourceDictionary>
<local:IntToBoolConverter x:Key="intToBool"/>
</ResourceDictionary>
</ContentView.Resources>
<ContentView.Content>
<StackLayout>
<Label Text="Page 1" FontSize="Large"/>
<Entry x:Name="txtName" Placeholder="Name"/>
<Button Text="Next" IsEnabled="{Binding Source={x:Reference txtName},
Path=Text.Length,
Converter={StaticResource intToBool}}"
Clicked="Button_Clicked"/>
</StackLayout>
</ContentView.Content>
</ContentView>
There are two problems:
1- I don't know how to handle the data (view model) between steps, to have only one object through all steps (Shall I use DI? if yes , then how in MVVMLight?)
2- How to to inject the content view into the main registration page dynamically in an MVVM fashion?
The solution I came up with, is creating an interface:
public interface INavigate
{
INavigate Next();
INavigate Previous();
}
all the ContentViews inherit from, for example the second ContentView implementation:
public INavigate Next()
=> new View3();
public INavigate Previous()
=> new View1();
the container page's Content property is bound to the view model's property CurrentView of type INavigate,
the command of the next button execute this:
CurrentView = CurrentView.Next();
and this is for the previous button:
CurrentView = CurrentView.Previous();

One WPF Window that displays different DataGrid's based on Menu selection?

I want to display different DataSource (SQL) queries in one 'DataGrid' based on Menu selections. Am I barking up the wrong tree by looking at UserControl's? How would this be implemented?
Edit:
I've finally found Changing user control on list selection which seems to answer my question pretty well, or at least modifies my question a little. So one Menu is to list all "Parts" available. The other Menu has MenuItems that correspond to locations and ultimately the inventory of said Parts at each location. Currently I am using a Click handler for each MenuItem and create a new instance of a specific UserControl for Parts and each location.
private void menuParts_Click(object sender, RoutedEventArgs e)
{
dgRoot.Children.Clear();
UserControl control = new ucParts();
this.dgRoot.Children.Add(control);
this.Title = "Inventory Manager - Parts";
}
and
private void menuSG1_Click(object sender, RoutedEventArgs e)
{
dgRoot.Children.Clear();
UserControl control = new ucSG1();
this.dgRoot.Children.Add(control);
this.Title = "Inventory Manager - SG1";
}
My question now is, can I create a reusable UserControl template that the Click handler can feed the location name to? The data is displayed, formatted, used, etc the same way, it's ultimately just the underlying DataSource query that is different.
You seemingly CAN do this. Just create the generic usercontrol Grid in my case.
MainWindow.xaml
<DockPanel>
<Menu DockPanel.Dock="Top" Name="menuMain" Height="27" HorizontalAlignment="Stretch" VerticalAlignment="Top" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<MenuItem Header="Parts">
<MenuItem Name="menuParts" Header="Parts" Click="menuParts_Click"/>
<Separator />
<MenuItem Name="addPart" Header="Add Part" Click="addPart_Click" />
</MenuItem>
<MenuItem Header="Inventory">
<MenuItem Name="menuBrady" Header="Brady" Click="menuBrady_Click"/>
<MenuItem Name="menuCO" Header="Community" Click="menuCO_Click"/>
<MenuItem Name="menuPoly" Header="Poly" Click="menuPoly_Click"/>
<MenuItem Name="menuSG1" Header="SG1" Click="menuSG1_Click"/>
<MenuItem Name="menuWS" Header="West Shore" Click="menuWS_Click"/>
</MenuItem>
</Menu>
<Grid Name="dgRoot" />
</DockPanel>
Then as shown in my Click handlers above, use them!

Double-wrapping Windows8 grid view

I'm working on a Windows 8 application and i have to create a different-sized tiles view. An issue is that i need my view to be double-wrapped: first, it should be wrapped horizontally (ie, each column should be 2 tiles in width). Such a view is going to be a very tall column. Next, it should wrap vertically.
The sketch of a view i'm going to create is given below. Are there any Win8 controls able to provide the described behavior ?
I've tried to use VariableSizedWrapGrid, but it seems it's unable to double-wrap it.
Ok, the time has passed and i've got no better solution than creating a custom columned model and using a grid with few VariableGridViews (one VariableGridViews per column).
Maybe, my XAML will help somebody.
<controls:VariableGridView ItemsSource="{Binding Columns}">
<controls:VariableGridView.ItemTemplate>
<DataTemplate>
<controls:VariableGridView ItemsSource="{Binding Tiles}">
<controls:VariableGridView.ItemTemplate>
<DataTemplate>
<Grid VariableSizedWrapGrid.ColumnSpan="{Binding Width}">
<Rectangle Fill="Red" Width="{Binding WidthPixels}" Height="{Binding HeightPixels}"></Rectangle>
</Grid>
</DataTemplate>
</controls:VariableGridView.ItemTemplate>
<controls:VariableGridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid VerticalAlignment="Center"
ItemHeight="150"
ItemWidth="150"
MaximumRowsOrColumns="2"
Orientation="Horizontal" Height="768"
AllowDrop="True"
Tapped="VariableSizedWrapGrid_Tapped"/>
</ItemsPanelTemplate>
</controls:VariableGridView.ItemsPanel>
</controls:VariableGridView>
</DataTemplate>
</controls:VariableGridView.ItemTemplate>
</controls:VariableGridView>
Model source code looks like (truncated)
public class TilesCollection
{
public ObservableCollection<ITile> Tiles {get; private set;}
}
public class ColumnedListModel
{
ObservableCollection<TilesCollection> m_columns = new ObservableCollection<TilesCollection>();
public ObservableCollection<TilesCollection> Columns
{
get
{
return m_columns;
}
}
// ....
}

Binding a View to my main window only shows me the type

I'm trying to bind a View to my ContentControl. Currently, it just shows me the type (eg NameSpace.ViewModel.MainWindowViewModel)
Although I will point out, I'm not sure if I'm approaching this correctly.
My simple set up is I have a View (UserControl) which is empty other than a single control (which has been placed just for the visual).
My MainWindow.xaml
<Window x:Class="DelegateGoodExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:DelegateGoodExample.ViewModel"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<viewModel:MainWindowViewModel x:Key="Vm" />
</Window.Resources>
<Grid>
<ContentControl Height="147" Margin="53,132,60,0"
VerticalAlignment="Top"
Content="{StaticResource Vm}" />
</Grid>
</Window>
(There is nothing in the code behind).
My MainWindowViewModel.cs
namespace DelegateGoodExample.ViewModel
{
public class MainWindowViewModel
{
private object _currentView;
public object CurrentView
{
get { return new View.QuickView(); }
set { _currentView = value; }
}
}
}
So, my question is,
Do I have to set a datacontext in this instance (and even if I do add it the results persist)?
What have I done wrong?
You are putting a viewmodel inside the ContentControl, not a view. Since your viewmodel class is not a UIElement and there is no DataTemplate to determine how it should be rendered, what gets displayed is simply its .ToString() representation.
An immediate fix would be:
<ContentControl Height="147" Margin="53,132,60,0"
VerticalAlignment="Top"
Content="{Binding Source={StaticResource Vm}, Path=View}" />
However, instead of doing things this way you should be putting your view inside the Grid directly, and the viewmodel should not have any knowledge of the view.