You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP银行账户列表拖拽:账户间转账落地逻辑实现求助

Hey there! Let’s walk through exactly how to implement that drag-and-drop transfer logic for your UWP bank app. I’ll break it down into actionable steps with code examples you can reuse.


Step 1: Define Your Account Data Model

First, you’ll need a robust account model that supports UI updates. Implement INotifyPropertyChanged so changes to the balance reflect immediately in your views:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class Account : INotifyPropertyChanged
{
    private decimal _balance;

    public string Id { get; set; }
    public string AccountName { get; set; }
    public decimal Balance
    {
        get => _balance;
        set
        {
            if (_balance != value)
            {
                _balance = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

In your ViewModel, use ObservableCollection for your account lists to enable automatic UI updates when items change:

using System.Collections.ObjectModel;

public class TransferViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Account> OutgoingAccounts { get; set; } = new ObservableCollection<Account>();
    public ObservableCollection<Account> IncomingAccounts { get; set; } = new ObservableCollection<Account>();

    // Don't forget to implement INotifyPropertyChanged here too if needed
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Step 2: Set Up the Outgoing Accounts List as a Drag Source

Configure your outgoing accounts ListView to allow dragging, and handle the DragItemsStarting event to pass the selected account data:

XAML:

<ListView x:Name="OutgoingAccountsListView"
          ItemsSource="{Binding OutgoingAccounts}"
          AllowDrop="True"
          DragItemsStarting="OutgoingAccountsListView_DragItemsStarting">
    <!-- Your item template (e.g., display account name and balance) -->
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding AccountName}" Margin="0 0 10 0"/>
                <TextBlock Text="{Binding Balance, StringFormat=C}"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Code-Behind:

private void OutgoingAccountsListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
    // Only allow dragging a single account
    if (e.Items.Count == 1 && e.Items[0] is Account sourceAccount)
    {
        // Use a custom data format to avoid conflicts with other drag operations
        e.Data.SetData("BankTransferAccount", sourceAccount);
        // Add a friendly caption to the drag UI
        e.DragUIOverride.Caption = $"Transfer from {sourceAccount.AccountName}";
        e.DragUIOverride.IsCaptionVisible = true;
    }
    else
    {
        // Cancel if multiple items or invalid data
        e.Cancel = true;
    }
}

Step 3: Make Each Incoming Account Item a Drop Target

You need to enable drop functionality on every individual incoming account list item. Use an ItemContainerStyle to attach the necessary events:

XAML:

<ListView x:Name="IncomingAccountsListView"
          ItemsSource="{Binding IncomingAccounts}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="AllowDrop" Value="True"/>
            <EventSetter Event="DragOver" Handler="IncomingAccountItem_DragOver"/>
            <EventSetter Event="Drop" Handler="IncomingAccountItem_Drop"/>
        </Style>
    </ListView.ItemContainerStyle>
    <!-- Your incoming account item template -->
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding AccountName}" Margin="0 0 10 0"/>
                <TextBlock Text="{Binding Balance, StringFormat=C}"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Handle Drag Over (Validate Drop):

private void IncomingAccountItem_DragOver(object sender, DragEventArgs e)
{
    // Check if the dragged data is our custom account format
    if (e.Data.Contains("BankTransferAccount"))
    {
        // Set accepted operation to Copy (since we're duplicating value, not moving the account)
        e.AcceptedOperation = DataPackageOperation.Copy;
        // Show visual feedback that drop is allowed
        e.DragUIOverride.IsGlyphVisible = true;
    }
    else
    {
        e.AcceptedOperation = DataPackageOperation.None;
    }
}

Step 4: Implement the Transfer Logic on Drop

This is the core part—when the user drops the outgoing account onto an incoming one, handle amount input, balance validation, and update the accounts:

private async void IncomingAccountItem_Drop(object sender, DragEventArgs e)
{
    // Get the target incoming account from the dropped item's DataContext
    if (sender is ListViewItem targetItem && targetItem.DataContext is Account targetAccount)
    {
        // Retrieve the source outgoing account from the drag data
        if (e.Data.GetData("BankTransferAccount") is Account sourceAccount)
        {
            // Prevent transferring to the same account
            if (sourceAccount.Id == targetAccount.Id)
            {
                await new ContentDialog
                {
                    Title = "Invalid Transfer",
                    Content = "You can't transfer to the same account.",
                    CloseButtonText = "OK"
                }.ShowAsync();
                return;
            }

            // Prompt user for transfer amount
            var amountInput = new TextBox
            {
                PlaceholderText = "Enter amount",
                Keyboard = Windows.UI.Xaml.Input.Keyboard.Numeric,
                Margin = new Windows.UI.Xaml.Thickness(0, 10, 0, 0)
            };

            var amountDialog = new ContentDialog
            {
                Title = "Enter Transfer Amount",
                Content = amountInput,
                PrimaryButtonText = "Transfer",
                CloseButtonText = "Cancel"
            };

            var result = await amountDialog.ShowAsync();
            if (result == ContentDialogResult.Primary)
            {
                if (decimal.TryParse(amountInput.Text, out decimal transferAmount) && transferAmount > 0)
                {
                    // Check if source account has enough balance
                    if (sourceAccount.Balance >= transferAmount)
                    {
                        // Update balances (INotifyPropertyChanged will refresh the UI)
                        sourceAccount.Balance -= transferAmount;
                        targetAccount.Balance += transferAmount;

                        // Show success message
                        await new ContentDialog
                        {
                            Title = "Transfer Successful",
                            Content = $"${transferAmount:N2} transferred from {sourceAccount.AccountName} to {targetAccount.AccountName}",
                            CloseButtonText = "OK"
                        }.ShowAsync();
                    }
                    else
                    {
                        await new ContentDialog
                        {
                            Title = "Insufficient Funds",
                            Content = $"Source account has only ${sourceAccount.Balance:N2}, which is less than ${transferAmount:N2}",
                            CloseButtonText = "OK"
                        }.ShowAsync();
                    }
                }
                else
                {
                    await new ContentDialog
                    {
                        Title = "Invalid Amount",
                        Content = "Please enter a valid positive number.",
                        CloseButtonText = "OK"
                    }.ShowAsync();
                }
            }
        }
    }
}

Bonus: MVVM-Friendly Approach (Optional)

If you’re following MVVM, you can decouple the drag-and-drop logic from the code-behind using the Microsoft.Xaml.Behaviors.Uwp.Managed NuGet package. This lets you bind drag/drop events to commands in your ViewModel:

  1. Install the NuGet package
  2. Add behaviors to your ListView items:
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:dragDrop="using:Microsoft.Xaml.Interactions.DragDrop"

<!-- For the outgoing list -->
<ListView ItemsSource="{Binding OutgoingAccounts}">
    <interactivity:Interaction.Behaviors>
        <dragDrop:DragStartingBehavior DragStartingCommand="{Binding DragAccountCommand}"/>
    </interactivity:Interaction.Behaviors>
</ListView>

<!-- For incoming list items -->
<ListView ItemsSource="{Binding IncomingAccounts}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="AllowDrop" Value="True"/>
            <Setter Property="interactivity:Interaction.Behaviors">
                <Setter.Value>
                    <interactivity:BehaviorCollection>
                        <dragDrop:DropBehavior DroppedCommand="{Binding DropAccountCommand}"/>
                    </interactivity:BehaviorCollection>
                </Setter.Value>
            </Setter>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

Then implement the commands in your ViewModel to handle the drag/drop logic without code-behind.


内容的提问来源于stack exchange,提问作者Mohammad Alqurm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:20:17