question

Imilio-3053 avatar image
0 Votes"
Imilio-3053 asked Imilio-3053 edited

How to use Binding in User Contros (MVVM)

Hi, In my app I open several user controls in the MainWindow via a tab control. Unfortunately, the binding does not work for the user controls.
Can someone help me to see what is wrong?

It should work like this: Clicking on button Info in Tab Control opens UserControl1 in MainWindow(already done with the code hier)and the data should be loaded(this does not work). Editing the info and clicking on button, the data is updated in Database.


 <Window x:Class="UserControlBinding.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:UserControlBinding"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800">
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="70"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
    
         <TabControl Grid.Row="0">
             <TabItem Header="Info">
                 <StackPanel Orientation="Horizontal"
                             HorizontalAlignment="Left">
                     <Button Command="{Binding Cmd}" 
                             CommandParameter="Info"
                             Height="30"
                             Width="30">
                         <TextBlock>Info</TextBlock>
                     </Button>
                 </StackPanel>
             </TabItem>
         </TabControl>
    
         <local:UserControl1 Grid.Row="1"/>
     </Grid>
 </Window>
    
    
 <UserControl x:Class="UserControlBinding.UserControl1"
              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:UserControlBinding"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800" Background="White">
    
     <UserControl.DataContext>
         <local:UC1ViewModel/>
     </UserControl.DataContext>
    
     <UserControl.Resources>
         <CollectionViewSource x:Key="View"/>
         <Style TargetType="{x:Type TextBox}">
             <Setter Property="Width" Value="200"/>
         </Style>
         <Style TargetType="{x:Type DatePicker}">
             <Setter Property="Width" Value="200"/>
         </Style>
         <Style TargetType="{x:Type Label}">
             <Setter Property="Width" Value="140"/>
             <Setter Property="HorizontalAlignment" Value="Left"/>
         </Style>
         <Style TargetType="StackPanel">
             <Setter Property="Margin" Value="0,0,0,5"/>
         </Style>
         <Style TargetType="{x:Type ComboBox}">
             <Setter Property="Width" Value="200"/>
         </Style>
         <Style TargetType="{x:Type Image}">
             <Setter Property="Height" Value="25"/>
             <Setter Property="Width" Value="25"/>
         </Style>
     </UserControl.Resources>
     <Grid Margin="20">
         <Grid.ColumnDefinitions >
             <ColumnDefinition Width="*"/>
             <ColumnDefinition Width="*"/>
         </Grid.ColumnDefinitions>
    
         <StackPanel Grid.Column="0" 
                     Orientation="Vertical">
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Name:"/>
                 <TextBox Text="{Binding CurrentData.Name}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Adress:"/>
                 <TextBox Text="{Binding CurrentData.Address}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="City:"/>
                 <ComboBox Text="{Binding CurrentData.City}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Mobile:"/>
                 <TextBox Text="{Binding CurrentData.Mobile}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Phone:"/>
                 <TextBox Text="{Binding CurrentData.Phone}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Fax:"/>
                 <TextBox Text="{Binding CurrentData.Fax}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="E-Mail:"/>
                 <TextBox Text="{Binding CurrentData.Email}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Website:"/>
                 <TextBox Text="{Binding CurrentData.Website}"/>
             </StackPanel>
    
             <StackPanel Orientation="Horizontal">
                 <Label Content="Date:"/>
                 <DatePicker SelectedDate="{Binding CurrentData.Date}"/>
             </StackPanel>
    
    
         </StackPanel>
    
         <!--Images-->
         <StackPanel Grid.Column="1" 
                     Orientation="Horizontal"
                     VerticalAlignment="Top"
                     HorizontalAlignment="Right">
             <GroupBox Header="Logo "
                       Height="190"
                       Width="325">
                 <Image Width="300"
                        Height="155"
                        Margin="5"
                        Source="{Binding }"/>
             </GroupBox>
             <!--Add delete Buttons-->
             <StackPanel Orientation="Vertical"
                         VerticalAlignment="Bottom">
                 <Button Command="{Binding Cmd}" 
                         CommandParameter="AddImage"
                         Content="Add"
                         Height="25"
                         Width="50"
                         Margin="0,0,0,5">
                 </Button>
                 <Button Command="{Binding Cmd}" 
                         CommandParameter="DeleteImage"
                         Content="Delete"
                         Height="25"
                         Width="50">
                 </Button>
             </StackPanel>
         </StackPanel>
         <!--End Content-->
    
         <!--region buttons-->
         <StackPanel Grid.Column="1"
                     Orientation="Horizontal"
                     VerticalAlignment="Bottom"
                     HorizontalAlignment="Right"
                     Margin="0">
             <Button Content="Cancel"
                     Width="50"
                     Margin="0,0,5,0"
                     Command="{Binding Cmd}" 
                     CommandParameter="Cancel"/>
             <Button Content="Save"
                     Width="50"
                     Command="{Binding Cmd}"
                     CommandParameter="Save"/>
         </StackPanel>
    
     </Grid>
 </UserControl>
    
    
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Data;
 using System.Windows.Input;
    
 namespace UserControlBinding
 {
     public class UC1ViewModel : INotifyPropertyChanged
     {
         private Data currentData;
         public Data CurrentData
         {
             get => this.currentData;
             set
             {
                 currentData = value;
                 OnPropertyChanged();
             }
         }
    
         private CollectionViewSource cvsCompany = new CollectionViewSource();
         public ICollectionView DataView
         {
             get
             {
                 if (cvsCompany.Source == null)
                 {
                     //cvsCompany.Source = ;
                 }
                 return cvsCompany.View;
             }
         }
    
         #region Commands
         public ICommand Cmd { get => new RelayCommand(CmdExec); }
         private void CmdExec(object parameter)
         {
             switch (parameter.ToString())
             {
                 case "Save":
                     //SaveData();
                     break;
    
                 case "Cancel":
                     //LoadData();
                     break;
    
                 case "AddImage":
    
                     break;
    
                 case "DeleteImage":
    
                     break;
    
                 default:
                     break;
             }
         }
         #endregion Commands
    
         public event PropertyChangedEventHandler PropertyChanged;
         internal void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
     }
    
     public class Data : INotifyPropertyChanged
     {
         public string Name { get; set; }
         public string Address { get; set; }
         public string City { get; set; }
         public string Mobile { get; set; }
         public string Phone { get; set; }
         public string Fax { get; set; }
         public string Email { get; set; }
         public string Website { get; set; }
         public string Date { get; set; }
         public string Logo { get; set; }
         public event PropertyChangedEventHandler PropertyChanged;
         internal void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
     }
    
     public class RelayCommand : ICommand
     {
         private readonly Predicate<object> _canExecute;
         private readonly Action<object> _action;
         public RelayCommand(Action<object> action) : this(action, null) { }
         public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
         public void Execute(object o) => _action(o);
         public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
         public event EventHandler CanExecuteChanged
         {
             add { CommandManager.RequerySuggested += value; }
             remove { CommandManager.RequerySuggested -= value; }
         }
     }
 }


windows-wpf
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi,@Imilio-3053. Whose answer did you accept and use to open UserControl1 in MainWindow ? What method do you use to connect and use the database?
Could you show the relevant code and steps?

0 Votes 0 ·

Hi @HuiLiu-MSFT , The following is the code I use to open the UserControl and connect to the database

 private UserControl1 userControl1;
    
 public ICommand Cmd { get => new RelayCommand(CmdExec); }
 private void CmdExec(object parameter)
 {
     switch (parameter.ToString())
     {
         case "Info":
             userControl1 = new UserControl1();
             UserControlInstance = userControl1;
             break;
     }
     OnPropertyChanged(nameof(UserControlInstance));
 }
    
    
    
 MySqlConnection SqlConn = new MySqlConnection();
 MySqlCommand SqlCmd = new MySqlCommand();
 DataTable SqlDt = new DataTable();
 String SqlQuery;
 MySqlDataAdapter SqlDA = new MySqlDataAdapter();
 MySqlDataReader SqlRd;
    
 ObservableCollection<Data> DataList = new ObservableCollection<Data>();
    
 internal ObservableCollection<Data> GetData()
 {
     DataList.Clear();
     foreach (DataRow row in SqlDt.Rows)
     {
         DataList.Add(instance);
     }
         return DataList;
 }
    
    
 public void UpLoadData()
 {
     SqlConn.ConnectionString = GetConnSting();
    
     SqlConn.Open();
     SqlCmd.Connection = SqlConn;
     SqlCmd.CommandText = "SELECT * FROM InfoDb.InfoTable";
     SqlRd = SqlCmd.ExecuteReader();
     SqlDt.Load(SqlRd);
     SqlRd.Close();
     SqlConn.Close();
 }
0 Votes 0 ·

Hi,@Imilio-3053. What is the code of your ContactModel class? How are you calling GetData and UpLoadData? What is the definition of the instance in your DataList.Add(instance);
Could you show me your complete project code to reproduce the problem and analyze it?

0 Votes 0 ·
Show more comments

1 Answer

HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered Imilio-3053 edited

I wrote an example based on your code. you could try to refer to it. I have added DataGrid in UserControl1.

200907-4.txt

Simple use of UserControl1 in MainWindow.
MainWindow.xaml:

 <Grid x:Name="grid">
     </Grid>

MainWindow.xaml.cs:

  public partial class MainWindow : Window 
   {
     public MainWindow()
     {
       InitializeComponent();
       UserControl1 uc=new UserControl1();
       uc.Width=600;
       uc.Height=400;
       grid.Children.Add(uc);
    
       DataContext =this;
     }
        
   }

The result:
200908-8.gif

Update:
I removed the DataGrid in the UserControl. Then assign DataList[0] to CurrentData.
UserControl:
201256-4.txt

The result:
201392-image.png


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


8.gif (51.8 KiB)
4.txt (10.5 KiB)
4.txt (9.5 KiB)
image.png (15.2 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @HuiLiu-MSFT , Thanks but your example can't help me. It works only if a DataGrid is used. I want to use only TextBox and ComboBox in UC. How to do it without DataGrid?

0 Votes 0 ·

Hi,@ Imilio-3053. I updated my answer, you could check it out.

0 Votes 0 ·

Hi @HuiLiu-MSFT , Thank you. That is what I wanted.

0 Votes 0 ·