0

我有一个 Windows Phone 8 应用程序,我有一个RelayCommand名为DiscoverExpansionModulesCommand. 我有一个Command属性绑定到的按钮DiscoverExpansionModulesCommand。当应用程序首次加载时,按钮会正确启用或禁用。但是,当在页面上并且我想更改命令是否可以执行时,该方法CanExecuteDiscoverExpansionModulesCommand()会正确触发并返回正确的 true 或 false 值,但按钮不会反映它。为什么按钮不更新它的 UI?我在这里找到了关于这个问题的另一篇文章http://social.msdn.microsoft.com/Forums/en-US/silverlightarchieve/thread/48a341e4-f512-4c33-befd-b614404b4920/

我的视图模型:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using MAL.Portable.Commands;
using MAL.Portable.Message;
using MAL.Portable.Model;
using System;
using System.Collections.Generic;
using System.Windows.Input;

namespace MAL.Portable.ViewModel
{
    public class SettingsViewModel : ViewModelBase
    {
        // Define an observable collection property that controls can bind to.
        private List<Setting> settings;
        private String controllerUrl;
        private String controllerPort;
        private String temperature;
        private Wifi wifi;
        private Boolean connected;
        private Boolean checkingConnection;


        public SettingsViewModel()
        {
            DiscoverExpansionModulesCommand = new RelayCommand(OnDiscoverExpansionModules, CanExecuteDiscoverExpansionModulesCommand);

            Messenger.Default.Register<RetrieveSettingsMessage>
            (
                 this, (action) => RetrievedListsMessage(action)
            );

            Messenger.Default.Send<GetSettingsMessage>(new GetSettingsMessage());
        }

        public ICommand DiscoverExpansionModulesCommand
        {
            get;
            private set;
        }

        public String ConnectionStatus
        {
            get
            {
                if (checkingConnection) 
                    return "checking";
                else
                    return connected ? "connected" : "not connnected";
            }
        }

        private Boolean CanExecuteDiscoverExpansionModulesCommand()
        {
            return connected;
        }

        private void OnDiscoverExpansionModules()
        {

        }

        private void CheckConnection()
        {
            wifi = null;
            if (!String.IsNullOrWhiteSpace(ControllerUrl) && !String.IsNullOrWhiteSpace(ControllerPort) && !checkingConnection)
            {
                checkingConnection = true;
                wifi = new ReefAngelWifi(controllerUrl, controllerPort);
                wifi.TestConnectionComplete += wifi_TestConnectionComplete;
                wifi.RequestFail += wifi_RequestFail;
                wifi.BeginTestConnection();
            }
        }

        private void wifi_RequestFail(object sender, RequestExceptionEventArgs e)
        {
            connected = false;
            checkingConnection = false;
            RaisePropertyChanged("ConnectionStatus");
        }

        private void wifi_TestConnectionComplete(object sender, TestConnectionEventArgs e)
        {
            connected = e.TestSuccessful;
            checkingConnection = false;
            DiscoverExpansionModulesCommand.CanExecute(null);
            RaisePropertyChanged("ConnectionStatus");
            RaisePropertyChanged("DiscoverExpansionModulesCommand");
        }

        private object RetrievedListsMessage(RetrieveSettingsMessage action)
        {
            settings = action.Settings;
            CheckConnection();
            return null;
        }

        private String GetStringValue(String key)
        {
            if (settings == null) return String.Empty;
            var item = settings.Find(x => x.Key == key);
            if (item == null) return String.Empty;
            else return item.Value;
        }

        private Boolean GetBooleanValue(String key)
        {
            if (settings == null) return false;
            var item = settings.Find(x => x.Key == key);
            if (item == null) return false;
            else return Boolean.Parse(item.Value);
        }
    }
}

和 XAML

<phone:PhoneApplicationPage 
    xmlns:ReefAngel="clr-namespace:MAL.WindowsPhone8"  
    xmlns:Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform.WP8"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:telerikPrimitives="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Primitives"
    x:Class="MAL.WindowsPhone8.ReefAngel.SettingsPage"
    xmlns:converter="clr-namespace:MAL.WindowsPhone8.Converters"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    DataContext="{Binding Settings, Source={StaticResource Locator}}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <phone:PhoneApplicationPage.Resources>
        <converter:BooleanToStringConverter x:Key="temperatureConverter" TrueString="Celsius" FalseString="Fahrenheit" />
        <converter:BooleanToStringConverter x:Key="timeFormatConverter" TrueString="24 hour" FalseString="12 hour" />
        <converter:BooleanToStringConverter x:Key="dateFormatConverter" TrueString="dd/mm/yyyy" FalseString="mm/dd/yyyy" />
    </phone:PhoneApplicationPage.Resources>

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" >
        <phone:Pivot Title="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}, StringFormat='\{0\} Settings'}">
            <phone:PivotItem Header="connection">
                <Grid>
                    <StackPanel Margin="12,0,0,0">
                        <TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Address"/>
                        <TextBox Height="72" TextWrapping="Wrap" Text="{Binding ControllerUrl, Mode=TwoWay}"/>
                        <TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Port"/>
                        <TextBox Height="72" TextWrapping="Wrap" Text="{Binding ControllerPort, Mode=TwoWay}"/>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Status : "/>
                            <TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="{Binding ConnectionStatus, Mode=OneWay}"/>
                        </StackPanel>

                    </StackPanel>
                </Grid>
            </phone:PivotItem>
            <phone:PivotItem Header="expansion">
                <Grid>
                    <Button Content="Discover Expansion Modules" x:Name="DiscoverButton" Command="{Binding DiscoverExpansionModulesCommand, Mode=OneWay}" />
                </Grid>
            </phone:PivotItem>

        </phone:Pivot>
    </Grid>

</phone:PhoneApplicationPage>

我正在使用 MVVM Light 便携式类库。

4

2 回答 2

7

RelayCommand.RaiseCanExecuteChanged()当您在方法中评估的条件发生变化时,您需要调用CanExecute

编辑

    private void wifi_RequestFail(object sender, RequestExceptionEventArgs e)
    {
        connected = false;
        checkingConnection = false;
        RaisePropertyChanged("ConnectionStatus");
        DiscoverExpansionModulesCommand.RaiseCanExecuteChanged();
    }

    private void wifi_TestConnectionComplete(object sender, TestConnectionEventArgs e)
    {
        connected = e.TestSuccessful;
        checkingConnection = false;
        DiscoverExpansionModulesCommand.CanExecute(null);
        RaisePropertyChanged("ConnectionStatus");
        RaisePropertyChanged("DiscoverExpansionModulesCommand");
        DiscoverExpansionModulesCommand.RaiseCanExecuteChanged();
    }

这不会导致循环,因为它只会告诉 RelayCommand 重新执行指定的 CanExecute 方法。在您的情况下,这仅意味着CanExecuteDiscoverExpansionModulesCommand已读取该属性。

于 2013-03-27T11:27:38.133 回答
1

这似乎是一个跨线程问题。并且弄清楚如何在 PCL 中调用 Dispatcher 很棘手,但我在这里找到了它: Update UI thread from portable class library

于 2013-03-27T16:49:10.613 回答