如何绑定和自动更新列表框wpf

时间:2014-08-11 22:31:15

标签: c# wpf multithreading binding listbox

好几个问题

第一

这是我的实施,但它没有工作,我怎么能让它运作?

    <Grid> // xaml part
    <Button Content="Start Crawling Root Sites - This Deletes All Data" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="279" Command="{Binding StartCrawling}" Click="click_start_Crawling"  />
    <ListBox Name="lstBoxEvents" HorizontalAlignment="Left"  Height="138" Margin="294,10,0,0" VerticalAlignment="Top" Width="312">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Margin="1">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="1" Text="{Binding ocEvents}"  />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>


        private void click_start_Crawling(object sender, RoutedEventArgs e) // inside mainwindow
    {
        PublicStaticFunctions.AddMsgToEvents("trial");
    }

    public static class PublicStaticFunctions // seperate class
{
    public static ObservableCollection<string> ocEvents = new ObservableCollection<string>();

    public static void AddMsgToEvents(string srMessage)
    {
        ocEvents.Insert(0, srMessage);
    }
}

运行多线程时的第二个问题,如果多个线程访问AddMsgToEvents函数并添加变量,列表框是否会自动刷新而没有任何问题?

非常感谢

1 个答案:

答案 0 :(得分:1)

这一行:

public static ObservableCollection<string> ocEvents = new ObservableCollection<string>();

这既不是依赖属性也不是实现INotifyPropertyChanged的属性,它也是静态的,如果你使用viewmodel就可以按照下面描述的方式进行,你可以在代码隐藏中进行,但是它会调用双重绘制。无论如何,您需要将其更改为DP或道具,如下所示:

private ObservableCollection<string> ocEvents = new ObservableCollection<string>();
public ObservableCollection<string> OcEvents
{
    get { return ocEvents; }
    set
    {
        if (Equals(value, ocEvents)) return;
        ocEvents = value;
        OnPropertyChanged();
    }
}
public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator] // Comment out if you don't have R#
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

绑定到静态类/属性有一些奇怪之处,你必须以不同的方式绑定。我现在要睡觉了,所以我无法提供和示例。在上面的例子中,我将创建一个vm,以及一个用于获取我的事件而不是使我的vm为unittestable的服务(创建提供事件的服务的接口,并在vm上具有event属性)。

AddMsgToEvents() 必须在调度程序线程上调用。糟糕的黑客是添加以下代码。用

调用它
    BeginInvoke(YourMethod);

将代码添加到vm的基类中,我知道调度程序应该以这种方式“使用”,但是要简单。

    public void BeginInvoke(Action action)
    {
        if( Application.Current.Dispatcher.CheckAccess())                
            Application.Current.Dispatcher.BeginInvoke(action);
        else
        {
            action();
        }
    }

    public void Invoke(Action action)
    {
        if (Application.Current.Dispatcher.CheckAccess())
            Application.Current.Dispatcher.BeginInvoke(action);
        else
        {
            action();
        }
    }


public static class PublicStaticFunctions

你可以在那里使用你的服务,只是取消静音并创建它的界面:D将你的道具移动到vm / codebehind,或者你需要对你的绑定进行一些修改,以获得支持或DP。简短的回答。

编辑:服务示例

public interface IEventService
{
    ObservableCollection<String> GetEvents();
    void AddEvent(String eventToAdd);
}

public  class EventService : IEventService
{
    private readonly ObservableCollection<string> events;

    public EventService(ObservableCollection<string> events)
    {
        this.events = events;
    }

    public EventService()
    {
        events = new ObservableCollection<string>();
    }

    public ObservableCollection<string> Events
    {
        get { return events; }
        //set { events = value; }
    }

    public ObservableCollection<String> GetEvents()
    {
        return events;
    }

    public void AddEvent(String eventToAdd)
    {
        events.Add(eventToAdd);
    }
}

将此接口提供给vm的ctor(TDD :))或codebehind ctor。将其分配并存储在IOC cotainer,servicelocator或其他任何内容中。

希望它有所帮助,

干杯,

了Stian