首页 > 解决方案 > PropertyChanged 事件在首次运行时不反映新的 Image.Source

问题描述

我正在开发移动应用程序,该应用程序有点模拟如何通过按顺序拖放图像来构建台式计算机。我DropGestureRecognizer使用AllowDrop设置True为拖放区Image控件和DragGestureRecognizer设置CanDragTrue拖动Image对象。

这个想法是Drag Image Objects将被拖放到 a Drop Zone Image Control,如果他们放弃了正确Drag Image的 ,Drop Zone将接受这个作为 theImage.Source并且另一个Drop Zone将堆叠在它前面以与下一个台式计算机组件一起使用。否则,它将被拒绝并且Image.Source将被设置为emptyor null

但是,我遇到了一个奇怪的问题,即在拖动的第一个不正确的图像上,它Image.Source被重置为emptynull按属性,但在实际的 UI 上却没有。在随后的 EventHandler 执行中,它确实会被重置。我有一个TapGestureRecognizer检查Drop Zone是否Image.Source有一套。

如果我的解释有点混乱,我很抱歉,因为英语不是我的母语,我很难解释它。所以请参考下面的 GIF 示例和我的代码:

查看 (.xaml):

<ContentPage.Content>
    <Grid RowDefinitions="Auto,60,*"
          ColumnDefinitions="*">

        <RelativeLayout Grid.Row="0" Grid.Column="0" HorizontalOptions="Center">
            <Image x:Name="imgCaseDropZone"
                   RelativeLayout.XConstraint="0"
                   RelativeLayout.YConstraint="0"
                   HeightRequest="{Binding ScreenWidth}"
                   WidthRequest="{Binding ScreenWidth}"
                   PropertyChanged="CaseDropZone_PropertyChanged"
                   BackgroundColor="LightGray">
                <Image.GestureRecognizers>
                    <DropGestureRecognizer AllowDrop="True" />
                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
                </Image.GestureRecognizers>
            </Image>
        </RelativeLayout>

        <Label Grid.Row="1" Grid.Column="0"
               x:Name="lblDirections"
               Text="Directions: Drag the components below in its proper order to the drop zone above."
               TextColor="Black"
               Padding="10"
               VerticalOptions="CenterAndExpand" 
               HorizontalOptions="CenterAndExpand" />

        <ScrollView Grid.Row="2"
                    Orientation="Horizontal"
                    Margin="5">
            <StackLayout Orientation="Horizontal">

                <!--#region Case -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding CaseIsVisible}">
                    <Image Grid.Row="0"
                           x:Name="imgCaseDragObject"
                           Source="{Binding CaseImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding CaseLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Case Cover -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding CaseCoverIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding CaseCoverImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding CaseCoverLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Case Screw -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding CaseScrewIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding CaseScrewImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding CaseScrewLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Hard Disk Drive -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding HardDiskDriveIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding HardDiskDriveImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding HardDiskDriveLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Heatsink -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding HeatsinkIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding HeatsinkImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding HeatsinkLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Memory Module -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding MemoryModuleIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding MemoryModuleImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding MemoryModuleLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Motherboard -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding MotherboardIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding MotherboardImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding MotherboardLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Motherboard Screw -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding MotherboardScrewIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding MotherboardScrewImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding MotherboardScrewLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Power Supply -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding PowerSupplyIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding PowerSupplyImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding PowerSupplyLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

                <!--#region Processor -->
                <Grid RowDefinitions="*,Auto"
                      IsVisible="{Binding ProcessorIsVisible}">
                    <Image Grid.Row="0"
                           Source="{Binding ProcessorImgSource}">
                        <Image.GestureRecognizers>
                            <DragGestureRecognizer CanDrag="True" />
                        </Image.GestureRecognizers>
                    </Image>

                    <Label Grid.Row="1"
                           Text="{Binding ProcessorLabel}"
                           TextColor="White"
                           FontSize="Medium"
                           BackgroundColor="Gray"
                           HorizontalTextAlignment="Center" />
                </Grid>
                <!--#endregion-->

            </StackLayout>
        </ScrollView>
    </Grid>


</ContentPage.Content>

查看代码 (.xaml.cs):

 [XamlCompilation(XamlCompilationOptions.Compile)]
 public partial class AssemblyPage : ContentPage
 {
      string caseSource;


      public AssemblyPage()
      {
           InitializeComponent();
      }

      int dragCount = 0;
      private void CaseDropZone_PropertyChanged(object sender, PropertyChangedEventArgs e)
      {
           if (e.PropertyName == "Source")
           {
                caseSource = imgCaseDropZone.Source.ToString().Split(':').Last().Trim();

                if (string.IsNullOrEmpty(caseSource))
                {
                     return;
                }

                if (caseSource != "img_assembly_case.png")
                {
                     imgCaseDropZone.Source = string.Empty;

                     lblDirections.Text = $"Drag Count: {++dragCount}";
                }
           }
      }

      private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
      {
           Application.Current.MainPage.DisplayAlert("", $"{imgCaseDropZone.Source}", "OK");
      }
 }

视图模型(.cs):

 public class AssemblyViewModel : BaseVM
 {
      public double ScreenWidth => Xamarin.Forms.Application.Current.MainPage.Width;

      #region Case
      bool caseIsVisible;
      public bool CaseIsVisible
      {
           get => caseIsVisible;
           set => SetProperty(ref caseIsVisible, value);
      }

      public string CaseImgSource { get; }
      public string CaseLabel { get; }
      #endregion

      #region CaseCover
      bool caseCoverIsVisible;
      public bool CaseCoverIsVisible
      {
           get => caseCoverIsVisible;
           set => SetProperty(ref caseCoverIsVisible, value);
      }

      public string CaseCoverImgSource { get; }
      public string CaseCoverLabel { get; }
      #endregion

      #region HardDiskDrive
      bool hardDiskDriveIsVisible;
      public bool HardDiskDriveIsVisible
      {
           get => hardDiskDriveIsVisible;
           set => SetProperty(ref hardDiskDriveIsVisible, value);
      }

      public string HardDiskDriveImgSource { get; }
      public string HardDiskDriveLabel { get; }
      #endregion

      #region CaseScrew
      bool caseScrewIsVisible;
      public bool CaseScrewIsVisible
      {
           get => caseScrewIsVisible;
           set => SetProperty(ref caseScrewIsVisible, value);
      }

      public string CaseScrewImgSource { get; }
      public string CaseScrewLabel { get; }
      #endregion

      #region Heatsink
      bool heatsinkIsVisible;
      public bool HeatsinkIsVisible
      {
           get => heatsinkIsVisible;
           set => SetProperty(ref heatsinkIsVisible, value);
      }

      public string HeatsinkImgSource { get; }
      public string HeatsinkLabel { get; }
      #endregion

      #region MemoryModule
      bool memoryModuleIsVisible;
      public bool MemoryModuleIsVisible
      {
           get => memoryModuleIsVisible;
           set => SetProperty(ref memoryModuleIsVisible, value);
      }

      public string MemoryModuleImgSource { get; }
      public string MemoryModuleLabel { get; }
      #endregion

      #region Motherboard
      bool motherboardIsVisible;
      public bool MotherboardIsVisible
      {
           get => motherboardIsVisible;
           set => SetProperty(ref motherboardIsVisible, value);
      }

      public string MotherboardImgSource { get; }
      public string MotherboardLabel { get; }
      #endregion

      #region MotherboardScrew
      bool motherboardScrewIsVisible;
      public bool MotherboardScrewIsVisible
      {
           get => motherboardScrewIsVisible;
           set => SetProperty(ref motherboardScrewIsVisible, value);
      }

      public string MotherboardScrewImgSource { get; }
      public string MotherboardScrewLabel { get; }
      #endregion

      #region PowerSupply
      bool powerSupplyIsVisible;
      public bool PowerSupplyIsVisible
      {
           get => powerSupplyIsVisible;
           set => SetProperty(ref powerSupplyIsVisible, value);
      }

      public string PowerSupplyImgSource { get; }
      public string PowerSupplyLabel { get; }
      #endregion

      #region Processor
      bool processorIsVisible;
      public bool ProcessorIsVisible
      {
           get => processorIsVisible;
           set => SetProperty(ref processorIsVisible, value);
      }

      public string ProcessorImgSource { get; }
      public string ProcessorLabel { get; }
      #endregion


      public AssemblyViewModel()
      {
           CaseIsVisible = true;
           CaseImgSource = "img_assembly_case.png";
           CaseLabel = "Case";

           CaseCoverIsVisible = true;
           CaseCoverImgSource = "img_assembly_case_cover.png";
           CaseCoverLabel = "Case Cover";

           CaseScrewIsVisible = true;
           CaseScrewImgSource = "img_assembly_case_screw.png";
           CaseScrewLabel = "Case Screw";

           HardDiskDriveIsVisible = true;
           HardDiskDriveImgSource = "img_assembly_hard_disk_drive.png";
           HardDiskDriveLabel = "Hard Disk Drive";

           HeatsinkIsVisible = true;
           HeatsinkImgSource = "img_assembly_heat_sink.png";
           HeatsinkLabel = "Heatsink";

           MemoryModuleIsVisible = true;
           MemoryModuleImgSource = "img_assembly_memory_module.png";
           MemoryModuleLabel = "Memory Module";

           MotherboardIsVisible = true;
           MotherboardImgSource = "img_assembly_motherboard.png";
           MotherboardLabel = "Motherboard";

           MotherboardScrewIsVisible = true;
           MotherboardScrewImgSource = "img_assembly_motherboard_screw.png";
           MotherboardScrewLabel = "Motherboard Screw";

           PowerSupplyIsVisible = true;
           PowerSupplyImgSource = "img_assembly_power_supply.png";
           PowerSupplyLabel = "Power Supply";

           ProcessorIsVisible = true;
           ProcessorImgSource = "img_assembly_processor.png";
           ProcessorLabel = "Processor";
      }
 }

GIF 中的当前构建演示:https ://imgur.com/a/oLeM9DV (我无法直接链接 GIF,因为它太大了)

标签: xamarinxamarin.formspropertychanged

解决方案


因为当你触发PropertyChanged事件的时候,拖拽动作已经完成,图片已经自动设置为目标。

只要我们用事件将它拖到目标上,我们就可以做出判断。然后在事件DragOver拖放完成时进行操作Drop

例如,更改 Image ( imgCaseDropZone) 的代码:

 <Image x:Name="imgCaseDropZone"
        RelativeLayout.XConstraint="0"
        RelativeLayout.YConstraint="0"
        RelativeLayout.WidthConstraint="400"
        RelativeLayout.HeightConstraint="400"
        BackgroundColor="LightGray"
                       >
      <Image.GestureRecognizers>
            <DropGestureRecognizer AllowDrop="{Binding CaseIsVisible}"   DragOver="CaseDropZone_DragOver"  Drop="CaseDropZone_Drop"/>
            <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
       </Image.GestureRecognizers>
 </Image>

在后面的代码中:

 private void CaseDropZone_DragOver(object sender, DragEventArgs e)
    {
        FileImageSource file = (FileImageSource)e.Data.Image;
        string name = file.File;
        if (name != "img_assembly_case.png")
        {
            e.Data.Image = string.Empty; // set the value string.Empty when drag it over the target,then it will fill the empty source to the image.
        }

    }

 private async void CaseDropZone_Drop(object sender, DropEventArgs e)
    {
        var ctx = (BindingContext as AssemblyViewModel);
        FileImageSource source = (FileImageSource)await e.Data.GetImageAsync();
        string name = source.File;
        if (name == "img_assembly_case.png")
        {
            ctx.CaseIsVisible = false;

            imgMotherboardDropZone.IsVisible = true;
        }
        else
        {
            Global.Score.PCAssembly -= 5;

            DisplayAlert($"Score: {Global.Score.PCAssembly}", "The pre-requisite component for this part has not yet been placed.", "OK");
        }
    }

其他图片是这样修改的。


推荐阅读