【问题标题】:Data Binding in Wpf MVVMWpf MVVM 中的数据绑定
【发布时间】:2017-08-20 04:08:34
【问题描述】:

我是 WPF 和 MVVM 的新手。

我尝试从 mysql 数据库中获取数据到 ObservableCollection,然后将其绑定到 UI。

问题是,我在模型层的第一个 ObservableCollection 中有数据,但是当我无法将数据发送到 ViewModel 层时,没有任何东西会绑定到 UI。

class Databasecon 
{
    int i = 0;

    // First Binding for the Database
    public ObservableCollection<Operator> operators { get; private set; }

    public Databasecon()
    {
        this.operators = new ObservableCollection<Operator>(); 
    }

    public void Datacon(string conn)
    {
        MySqlConnection con = null;
        MySqlCommand com = null;
        MySqlDataReader myreader = null;
        int columnOrdinaloperatorname = -1;

        con = new MySqlConnection(conn);
        try
        {
            if (com == null)
            {
                com = new MySqlCommand("SELECT operator_name FROM operators", con);
                com.Connection.Open();

                myreader = com.ExecuteReader();
                columnOrdinaloperatorname = myreader.GetOrdinal("operator_name");

                while (myreader.Read())
                {
                    this.operators.Add(new Operator() { operatorname = myreader.GetString(columnOrdinaloperatorname).ToString() });

                    i++;
                }  
            }

            MessageBox.Show(operators.Count.ToString());
        }
        catch (MySqlException ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            if (myreader != null)
                myreader.Close();

            if (com != null)
            {
                if (com.Connection != null)
                    com.Connection.Close();
            }
        }
    }
}

class Operator
{
    public string operatorname { get ; set; }
}

class collect : INotifyPropertyChanged
{
    private Databasecon databasecon = null;

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Operator> operators
    {
        get
        {
            if (this.databasecon.operators != null)
            {
                return this.databasecon.operators;                   
            }
            else
            {
                return null;
            }
        }
        set
        {
            this.operators = value; RaisePropertyChanged("operators");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public collect()
    { 
        this.databasecon = new Databasecon();
    }
}

Xaml 代码是:

 <Window.DataContext>
    <vm:collect/>
</Window.DataContext>
<Grid>
    <TextBlock Margin="459,51,-459,-51"><InlineUIContainer>
                <TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="{Binding Path=operators}"  Width="198" FontSize="28" Height="66"/>
            </InlineUIContainer></TextBlock>
    <ListBox x:Name="listBox"  HorizontalAlignment="Left" Height="102" Margin="115,240,0,0" VerticalAlignment="Top" Width="339" ItemsSource="{Binding operators}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock >
                        <Run Text="{Binding operatorname}"></Run>
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

谁能帮我解决这个问题?

【问题讨论】:

    标签: wpf mvvm observablecollection


    【解决方案1】:

    您的绑定对我来说似乎很好 - 这是我为测试它们所做的:

    <Window.DataContext>
        <vm:collect/>
    </Window.DataContext>
    <Grid>
        <Button VerticalAlignment="Top" HorizontalAlignment="Left" Command="{Binding AddThings}" Height="25" Width="Auto">Add Stuff</Button>
        <TextBlock Margin="459,51,-459,-51"><InlineUIContainer>
                <TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="{Binding Path=operators}"  Width="198" FontSize="28" Height="66"/>
            </InlineUIContainer></TextBlock>
        <ListBox x:Name="listBox"  HorizontalAlignment="Left" Height="102" Margin="115,240,0,0" VerticalAlignment="Top" Width="339" ItemsSource="{Binding operators}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock >
                        <Run Text="{Binding operatorname}"></Run>
                        </TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    

    C#:

    class Databasecon
    {
        int i = 0;
    
        // First Binding for the Database
        public ObservableCollection<Operator> operators { get; private set; }
    
        public Databasecon()
        {
            this.operators = new ObservableCollection<Operator>();
        }
    
        public void Datacon()
        {
                this.operators.Add(new Operator() { operatorname = "Hello world!"});
        }
    }
    
    class Operator
    {
        public string operatorname { get; set; }
    }
    
    class collect : INotifyPropertyChanged
    {
        private Databasecon databasecon = null;
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public ICommand AddThings { get; set; }
    
        public ObservableCollection<Operator> operators
        {
            get
            {
                if (this.databasecon.operators != null)
                {
                    return this.databasecon.operators;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                this.operators = value; RaisePropertyChanged("operators");
            }
        }
    
        private void RaisePropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        public collect()
        {
            this.databasecon = new Databasecon();
            AddThings = new SimpleCommand(() => databasecon.Datacon()); 
        }
    }
    
    public class SimpleCommand : ICommand
    {
        private Action _command; 
    
        public SimpleCommand(Action command)
        {
            _command = command; 
        }
    
        public bool CanExecute(object parameter)
        {
            return true; 
        }
    
        public event EventHandler CanExecuteChanged;
    
        public void Execute(object parameter)
        {
            if (_command != null)
                _command();
        }
    }
    

    您的问题可能在于您设置数据上下文的方式。目前,您的窗口每次实例化时都会创建视图模型的新实例,但由于您没有设置名称,我假设此实例仅由窗口使用。您可以将 vm 设为公共属性并调用窗口持有的实例来填充集合:

    <Window.DataContext>
        <vm:collect x:Name="Collect"/>
    </Window.DataContext>
    
    
    window.Collect.Datacon("[My connection string]");
    

    或者将您打算使用的实例传递给视图模型构造函数并在那里设置:

     public MainWindow(object viewModel)
        {
            DataContext = viewModel; 
            InitializeComponent();
        }
    

    【讨论】:

    • 感谢您的回答。您能向我解释一下我如何在 UI 加载中使用 ICommand 接口而不是按钮来进行此绑定
    • 我不太清楚你的意思。你的意思是你想在 UI 加载时填充你的列表吗?在这种情况下,您只需要在 collect 构造函数中添加对 databasecon.Datacon("[connection string]") 的调用。
    • 感谢您的帮助,它现在可以工作了 stackoverflow.com/questions/18593720/window-load-event-in-mvvm 这正是我所需要的
    猜你喜欢
    • 2015-05-24
    • 1970-01-01
    • 2011-02-01
    • 2014-08-09
    • 1970-01-01
    • 2019-06-23
    • 2020-09-27
    • 1970-01-01
    相关资源
    最近更新 更多