Событие PropertyChanged не отражает новое изображение.Источник при первом запуске

#xamarin #xamarin.forms #propertychanged

Вопрос:

Я работаю над мобильным приложением, которое как бы имитирует создание настольного компьютера путем перетаскивания изображения по порядку. Я работаю DropGestureRecognizer с AllowDrop настройками True для Image элементов управления зоной перетаскивания и DragGestureRecognizer с CanDrag настройками True для объектов перетаскивания Image .

Идея заключается Drag Image Objects в том , что они будут перетащены и сброшены в a Drop Zone Image Control , и если они сбросили правильный Drag Image , Drop Zone то примут это как Image.Source то, а другой Drop Zone будет сложен перед ним для работы со следующим компонентом настольного компьютера. В противном случае он будет отклонен, и Image.Source будет установлено значение empty или null .

Однако я сталкиваюсь со странной проблемой, из-за которой при первом неправильном перетаскивании изображения свойство Image.Source сбрасывается в empty или null по, но в реальном пользовательском интерфейсе этого не происходит. При последующем выполнении обработчика событий он сбрасывается. У меня есть 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, потому что он слишком большой)

Комментарии:

1. Где вы устанавливаете источник обращений в зону imgCaseDropZone ? Если возможно, вы можете поделиться образцом.

2. Привет @LeoZhu-MSFT, код уже есть. у меня нет явного кода, который устанавливает imgCaseDropZone.Source изображение, потому что оно обрабатывается распознавателем DropGesture.

3. вот копия моего кода на GitHub: github.com/SkyEngine-OSP/PC-Trainer-App

Ответ №1:

Потому что, когда вы запускаете PropertyChanged событие, действие перетаскивания уже завершено, и изображение автоматически настроено на цель.

Мы могли бы вынести такое суждение, как только перетащим его на цель с DragOver помощью события.Затем выполните действие, когда перетаскивание завершится Drop событием.

Например,измените коды изображения ( 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");
        }
    }
 

Другие изображения изменяются подобным образом.