silverlight中如何防止UI线程锁定

发布于 2024-11-26 18:54:32 字数 3608 浏览 1 评论 0原文

在视图中,我有一个按钮,可以调用我的视图模型

search.xaml

 <TextBox x:Name="txtSearchField"
             Grid.Column="0"
             Style="{StaticResource SearchTxtBoxStyle}"
             Text="{Binding SearchTerm, Mode=TwoWay}"
             KeyDown="txtSearchField_KeyDown"
             ToolTipService.ToolTip="{StaticResource TTsearchField}">
        <i:Interaction.Triggers>
            <ei:KeyTrigger Key="Enter">
                <ei:CallMethodAction
                    TargetObject="{Binding}"
                    MethodName="GetSearchResult"/>
            </ei:KeyTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    <StackPanel x:Name="searchButtons"
                Grid.Row="0"
                Grid.Column="1"
                Margin="3,2,5,2"
                Orientation="Horizontal">
        <Button x:Name="SearchButton"
                Margin="13,1,9,-1"
                ap:AttachedProperties.TabIndex="2"
                Content="{StaticResource btnSearch}"
                Style="{StaticResource blackButton}"
                ToolTipService.ToolTip="{StaticResource TTSavebtn}" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction
                    TargetObject="{Binding}"
                    MethodName="GetSearchResult"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

中的方法,我在视图中还有一个 IsBusy 指示器

 <Grid>
        <!-- Bind IsBusy to IsBusy -->
        <toolkit:BusyIndicator Name="isBusyIndicator" 
            IsBusy="{Binding IsBusy, Mode=TwoWay}"  />
    </Grid>

(我在这个项目中使用 SimpleMVVM 工具包)

在视图模型中,我将我的方法声明为以及 IsBusyIndi​​cator 等的属性。

searchviewmodel.xaml

 public void GetSearchResult()
    {
        //query

       // IsBusy = true;  //Originally set the IsBusyFlag here to see if it would fire 

            SearchResults = this._DataModel.GetSearchResults(this.SearchTerm);
            this.SearchHistory = this._DataModel.AddSearchHistoryItem(this.SearchTerm);   
    }


private bool _isBusy;
    public bool IsBusy
    {
        get { return _isBusy; }
        set
        {
            _isBusy = value;
            NotifyPropertyChanged(m => m.IsBusy);
        }
    }

然后在模型中,我对 WCF 服务进行异步调用。

public ObservableCollection<QueryResponse> GetSearchResults(string searchQuery)
    { 
        SearchClient sc = new SearchClient();
        sc.QueryCompleted +=new EventHandler<QueryCompletedEventArgs>(sc_QueryCompleted);
        sc.QueryAsync(new Query { QueryText = searchQuery });
        return this.SearchResults;      
    }  

    void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
    {
        try
        {
            if (SearchResults != null)
            {
                this.SearchResults.Clear();
                this.SearchResults.Add(e.Result);

            }
            else
            {
                this.SearchResults.Add(e.Result);

            }
           // IsBusy = false;

        }
        catch(Exception ex)
        {
            ex.StackTrace.ToString();
        }
    }

搜索控件通过应用了 dataTempalte 选择器类的列表框控件加载结果。

我看到的问题是,由于此调用是从 UI 调用的,因此 UI 线程会锁定,直到为集合选择数据模板并返回结果为止。到目前为止,IsBusy 指示器甚至还没有触发。

我的问题是有人可以指出我应该如何进行这些调用以便 UI 线程不被锁定吗?我是否应该寻找某种后台线程等来进行调用,以便 UI 线程可以调用 IsBusy 指示器等。

如果您需要更多详细信息或其他示例,请告诉我。

提前致谢

Within a view I have a button that makes a call to a method within my view model

search.xaml

 <TextBox x:Name="txtSearchField"
             Grid.Column="0"
             Style="{StaticResource SearchTxtBoxStyle}"
             Text="{Binding SearchTerm, Mode=TwoWay}"
             KeyDown="txtSearchField_KeyDown"
             ToolTipService.ToolTip="{StaticResource TTsearchField}">
        <i:Interaction.Triggers>
            <ei:KeyTrigger Key="Enter">
                <ei:CallMethodAction
                    TargetObject="{Binding}"
                    MethodName="GetSearchResult"/>
            </ei:KeyTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    <StackPanel x:Name="searchButtons"
                Grid.Row="0"
                Grid.Column="1"
                Margin="3,2,5,2"
                Orientation="Horizontal">
        <Button x:Name="SearchButton"
                Margin="13,1,9,-1"
                ap:AttachedProperties.TabIndex="2"
                Content="{StaticResource btnSearch}"
                Style="{StaticResource blackButton}"
                ToolTipService.ToolTip="{StaticResource TTSavebtn}" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction
                    TargetObject="{Binding}"
                    MethodName="GetSearchResult"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

I also have within the view an IsBusy Indicator

 <Grid>
        <!-- Bind IsBusy to IsBusy -->
        <toolkit:BusyIndicator Name="isBusyIndicator" 
            IsBusy="{Binding IsBusy, Mode=TwoWay}"  />
    </Grid>

(I am using SimpleMVVM toolkit with this project)

Within the view model I have my method declared as well as the properties for an IsBusyIndicator etc.

searchviewmodel.xaml

 public void GetSearchResult()
    {
        //query

       // IsBusy = true;  //Originally set the IsBusyFlag here to see if it would fire 

            SearchResults = this._DataModel.GetSearchResults(this.SearchTerm);
            this.SearchHistory = this._DataModel.AddSearchHistoryItem(this.SearchTerm);   
    }


private bool _isBusy;
    public bool IsBusy
    {
        get { return _isBusy; }
        set
        {
            _isBusy = value;
            NotifyPropertyChanged(m => m.IsBusy);
        }
    }

Then within the model I have my async call to the WCF service

public ObservableCollection<QueryResponse> GetSearchResults(string searchQuery)
    { 
        SearchClient sc = new SearchClient();
        sc.QueryCompleted +=new EventHandler<QueryCompletedEventArgs>(sc_QueryCompleted);
        sc.QueryAsync(new Query { QueryText = searchQuery });
        return this.SearchResults;      
    }  

    void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
    {
        try
        {
            if (SearchResults != null)
            {
                this.SearchResults.Clear();
                this.SearchResults.Add(e.Result);

            }
            else
            {
                this.SearchResults.Add(e.Result);

            }
           // IsBusy = false;

        }
        catch(Exception ex)
        {
            ex.StackTrace.ToString();
        }
    }

The search control loads the results through a listbox control that has a dataTempalte selector class applied.

The issue I am seeing is since this call is being invoked from the UI the UI thread is locking up until the datatemplates are selected for the collection and the results returned. To this point the IsBusy indicator is not even firing.

My question is can someone point me in the direction on how these calls should be made so that the UI thread is not locked? Should I be looking for some sort of background thread etc to make the call so that the UI thread can invoke the IsBusy indicator etc.

Please let me know if you need more detail or additional samples.

thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

放我走吧 2024-12-03 18:54:32

这里的问题是您锁定 UI 线程,虽然从表面上看,鉴于事物的结构方式,一切都应该正常工作,如果没有模型中 SearchResult 中的代码,我无法确定您的问题可能在哪里。

另外,您在 *sc_QueryCompleted* 中存在空引用问题,您检查 SearchResults 是否不等于空,但在您的 else 条件下,您尝试向刚刚验证的对象添加值将为空。更正后的版本如下:

if (SearchResults != null) {
    this.SearchResults.Clear();
    this.SearchResults.Add(e.Result);
} else {
    //I'm guessing at the type from your code
    this.SearchResults = new List<SearchResult)();
    this.SearchResults.Add(e.Result);
}

The issue here is your locking the UI thread, While on the surface it appears that everything should work correctly given how things are structured, without the code thats in SearchResult in your model, I can't say for sure where you issue might be.

Also, you have a null reference issue in *sc_QueryCompleted*, your check if SearchResults is not equal to null, but in your else condition you attempt to add a value to the object you've just verified will be null. The corrected version is below:

if (SearchResults != null) {
    this.SearchResults.Clear();
    this.SearchResults.Add(e.Result);
} else {
    //I'm guessing at the type from your code
    this.SearchResults = new List<SearchResult)();
    this.SearchResults.Add(e.Result);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文