开发者

WPF模拟实现Gitee泡泡菜单的示例代码

wpF实现 Gitee泡泡菜单

框架使用大于等于.NET40

Visual Studio 2022;

项目使用 MIT 开源许可协议;

WPF模拟实现Gitee泡泡菜单的示例代码

  • 需要实现泡泡菜单需要使用Canvas画布进行添加内容;
  • 保证颜色随机,位置不重叠;
  • 点击泡泡获得当前泡泡的值;

实现代码

1) BubblleCanvas.cs 代码如下;

usingSystem.Windows;
usingSystem.Windows.Controls;
usingWPFDevelopers.Helpers;
usingWPFDevelopers.Utilities;

namespaceWPFDevelopers.Controls
{
publicclassBubblleCanvas:Canvas
{
privatedouble_bubbleItemX;
privatedouble_bubbleItemY;

privateint_number;
privatedouble_size;
privateconstint_maxSize=120;

protectedoverrideSizeArrangeOverride(SizearrangeSize)
{
varwidth=arrangeSize.Width;
varheight=arrangeSize.Height;

doubleleft=0d,top=0d;
for编程(vary=0;y<(int)height/_maxSize;y++)
{
doubleyNum=y+1;
yNum=_maxSize*yNum;
for(varx=0;x<(int)width/_maxSize;x++)
{
if(_number>InternalChildren.Count-1)
returnarrangeSize;

varitem=InternalChildren[_number]asFrameworkElement;

if(DoubleUtil.IsNaN(item.ActualWidth)||DoubleUtil.IsZero(item.ActualWidth)||DoubleUtil.IsNaN(item.ActualHeight)||DoubleUtil.IsZero(item.ActualHeight))
ResizeItem(item);

_bubbleItemX=Canvas.GetLeft(item);
_bubbleItemY=Canvas.GetTop(item);

if(double.IsNaN(_bubbleItemX)||double.IsNaN(_bubbleItemY))
{
doublexNum=x+1;
xNum=_maxSize*xNum;
_bubbleItemX=ControlsHelper.NextDouble(left,xNum-_size*ControlsHelper.NextDouble(0.6,0.9));
var_width=_bubbleItemX+_size;
_width=_width>width?width-(width-_bubbleItemX)-_size:_bubbleItemX;
_bubbleItemX=_width;
_bubbleItemY=ControlsHelper.NextDouble(top,yNum-_size*ControlsHelper.NextDouble(0.6,0.9));
var_height=_bubbleItemY+_size;
_height=_height>height?height-(height-_bubbleItemY)-_size:_bubbleItemY;
_bubbleItemY=_height;

}
Canvas.SetLeft(item,_bubbleItemX);
Canvas.SetTop(item,_bubbleItemY);
left=left+_size;

_number++;

item.Arrange(newRect(newPoint(_bubbleItemX,_bubbleItemY),newSize(_size,_size)));
}
left=0d;
top=top+_maxSize;
}

returnarrangeSize;
}
privatevoidResizeItem(FrameworkElementitem)
{
if(DoubleUtil.GreaterThanOrClose(item.DesiredSize.Width,55))
_size=ControlsHelper.GetRandom.Next(80,_maxSize);
else
_size=ControlsHelper.GetRandom.Next(55,_maxSize);
item.Width=_size;
item.Height=_size;
}
}
}

2) ControlsHelper.cs 代码如下;

  • 随机Double值;
  • 随机颜色;
privatestaticlong_tick=DateTime.Now.Ticks;
publicstaticRandomGetRandom=newRandom((int)(_tick&0xffffffffL)|(int)(_tick>>32));

publicstaticdoubleNextDouble(doubleminiDouble,doublemaxiDouble)
{
if(GetRandom!=null)
{
returnGetRandom.NextDouble()*(maxiDouble-miniDouble)+miniDouble;
}
else
{
return0.0d;
}
}
publicstaticBrushRandomBrush()
{
varR=GetRandom.Next(255);
varG=GetRandom.Next(255);
varB=GetRandom.Next(255开发者_Go学习);
varcolor=Color.FromRgb((byte)R,(byte)G,(byte)B);
varsolidColorBrush=newSolidColorBrush(color);
returnsolidColorBrush;
}

3) BubbleControl.cs 代码如下;

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Collections.ObjectModel;
usingSystem.Diagnostics;
usingSystem.Linq;
usingSystem.Windows;
usingSystem.Windows.Controls;
usingSystem.Windows.Input;
usingSystem.Windows.Media;
usingSystem.Windows.Shapes;
usingWPFDevelopers.Helpers;

namespaceWPFDevelopers.Controls
{
[TemplatePart(Name=BorderTemplateName,Type=typeof(Border))]
[TemplatePart(Name=EllipseTemplateName,Type=typeof(Ellipse))]
[TemplatePart(Name=RotateTransformTemplateName,Type=typeof(RotateTransform))]
publicclassBubblleControl:Control
{
privateconststringBorderTemplateName="PART_Border";
privateconststringEllipseTemplateName="PART_Ellipse";
privateconststringRotateTransformTemplateName="PART_EllipseRotateTransform";
privateconststringListBoxTemplateName="PART_ListBox";

privatestaticreadonlyType_typeofSelf=typeof(BubblleControl);

prjavascriptivateObservableCollection<BubblleItem>_items=newObservableCollection<BubblleItem>();


privateBorder_border;
privateEllipse_ellipse;
privateRotateTransform_rotateTransform;
privateBrush[]brushs;
privateItemsControl_listBox;
privatestaticRoutedCommand_clieckCommand;

classBubblleItem
{
publicstringText{get;set;}
publicBrushBg{get;set;}
}

staticBubblleControl()
{
InitializeCommands();
DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf,newFrameworkPropertyMetadata(_typeofSelf));
}

#regionEvent

publicstaticreadonlyRoutedEventClickEvent=EventManager.RegisterRoutedEvent("Click",RoutingStrategy.Bubble,typeof(RoutedEventHandler),_typeofSelf);
publiceventRoutedEventHandlerClick
{
add{AddHandler(ClickEvent,value);}
remove{RemoveHandler(ClickEvent,value);}
}

#endregion

#regionCommand

privatestaticRoutedCommand_clickCommand=null;

privatestaticvoidInitializeCommands()
{
_clickCommand=newRoutedCommand("Click",_typeofSelf);

CommandManager.RegisterClassCommandBinding(_typeofSelf,newCommandBinding(_clickCommand,OnClickCommand,OnCanClickCommand));
}

publicstaticRoutedCommandClickCommand
{
get{return_clickCommand;}
}

privatestaticvoidOnClickCommand(objectsender,ExecutedRoutedEventArgse)
{
varctrl=senderasBubblleControl;

ctrl.SetValue(SelectedTextPropertyKey,e.Parameter?.ToString());
ctrl.RaiseEvent(newRoutedEventArgs(ClickEvent));
}

privatestaticvoidOnCanClickCommand(objectsender,CanExecuteRoutedEventArgse)
{
e.CanExecute=true;
}

#endregion

#regionreadonlyProperties

privatestaticreadonlyDependencyPropertyKeySelectedTextPropertyKey=
DependencyProperty.RegisterReadOnly("SelectedText",typeof(string),_typeofSelf,newPropertyMetadata(null));
publicstaticreadonlyDependencyPropertySelectedTextProperty=SelectedTextPropertyKey.DependencyProperty;
publicstringSelectedText
{
get{return(string)GetValue(SelectedTextProperty);}
}
publicnewstaticreadonlyDependencyPropertyBorderBackgroundProperty=
DependencyProperty.Register("BorderBackground",typeof(Brush),typhppeof(BubblleControl),
newPropertyMetadata(null));

publicnewstaticreadonlyDependencyPropertyEarthBackgroundProperty=
DependencyProperty.Register("EarthBackground",typeof(Brush),typeof(BubblleControl),
newPropertyMetadata(Brushes.DarkOrchid));
publicBrushBorderBackground
{
get=>(Brush)this.GetValue(BorderBackgroundProperty);
set=>this.SetValue(BorderBackgroundProperty,(object)value);
}
publicBrushEarthBackground
{
get=>(Brush)this.GetValue(EarthBackgroundProperty);
set=>this.SetValue(EarthBackgroundProperty,(object)value);
}
#endregion

#regionProperty

publicstaticreadonlyDependencyPropertyItemsSourceProperty=
DependencyProperty.Register("ItemsSource",typeof(IEnumerable<string>),typeof(BubblleControl),newPropertyMetadata(null,OnItemsSourcePropertyChanged));
publicIEnumerable<string>ItemsSource
{
get{return(IEnumerable<string>)GetValue(ItemsSourceProperty);}
set{SetValue(ItemsSourceProperty,value);}
}

privatestaticvoidOnItemsSourcePropertyChanged(DependencyObjectobj,DependencyPropertyChangedEventArgse)
{
varctrl=objasBubblleControl;
varnewValue=e.NewValueasIEnumerable<string>;

if(newValue==null)
{
ctrl._items.Clear();
return;
}

foreach(variteminnewValue)
{
ctrl._items.Add(newBubblleItem{Text=item,Bg=ControlsHelper.RandomBrush()});
}
}

#endregion

#regionOverride

publicoverridevoidOnApplyTemplate()
{
base.OnApplyTemplate();
_border=GetTemplateChild(BorderTemplateName)asBorder;
_ellipse=GetTemplateChild(EllipseTemplateName)asEllipse;
_rotateTransform=GetTemplateChild(RotateTransformTemplateName)asRotateTransform;
Loaded+=delegate
{
varpoint=_border.TranslatePoint(newPoint(_border.ActualWidth/2,_border.ActualHeight/2),
_ellipse);
_rotateTransform.CenterX=point.X-_ellipse.ActualWidth/2;
_rotateTransform.CenterY=point.Y-_ellipse.ActualHeight/2;
};
_listBox=GetTemplateChild(ListBoxTemplateName)asItemsControl;
_listBox.ItemsSource=_items;
}

#endregion
}
}

4) BubblleControl.xaml 代码如下;

<ResourceDictionaryXMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WPFDevelopers.Controls">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionarySource="Basic/ControlBasic.xaml"/>
<ResourceDictionarySource="Basic/Animations.xaml"/>
</ResourceDictionary.MergedDictionaries>

<StyleTargetType="controls:BubblleControl"BasedOn="{StaticResourceControlBasicStyle}">
<SetterProperty="Width"Value="400"/>
<SetterProperty="Height"Value="400"/>
<SetterProperty="Background"Value="{StaticResourceWhiteSolidColorBrush}"/>
<SetterProperty="BorderThickness"Value="1"/>
<SetterProperty="BorderBrush"Value="{StaticResourceSecondaryTextSolidColorBrush}"/>
<SetterProperty="BorderBackground"Value="{StaticResourceBaseSolidColorBrush}"/>
<SetterProperty="Template">
<Setter.Value>
<ControlTemplateTargetType="controls:BubblleControl">
<Gridwidth="{TemplateBindingWidth}"Height="{TemplateBindingHeight}">
<BorderBorderBrush="{TemplateBindingBorderBrush}"
BorderThickness="{TemplateBindingBorderThickness}"
Background="{TemplateBindingBorderBackground}"
Margin="45"
CornerRadius="400"
x:Name="PART_Border">
<EllipseFill="{TemplateBindingBackground}"Margin="20"/>
</Border>
<EllipseFill="{TemplateBindingEarthBackground}"
Width="26"Height="26"
RenderTransformOrigin=".5,.5"
x:Name="PART_Ellipse"
VerticalAlignment="Top"Margin="0,35,0,0">
<Ellipse.RenderTransform>
<RotateTransformx:Name="PART_EllipseRotateTransform"></RotateTransform>
</Ellipse.RenderTransform>
<Ellipse.Triggers>
<EventTriggerRoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationStoryboard.TargetProperty="(Ellipse.RenderTransform).(RotateTransform.Angle)"
RepeatBehavior="Forever"
From="0"To="360"
Duration="00:00:13"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
<ItemsControlx:Name="PART_ListBox"
ItemsSource="{TemplateBindingItemsSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<GridWidth="{TemplateBindingWidth}"
Hepythonight="{TemplateBindingHeight}">

<EllipseFill="{BindingBg}"
Opacity=".4"/>
<EllipseStroke="{BindingBg}"
StrokeThickness=".8"/>
</Grid>

<TextblockVerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="10,0">
<Hyperlink
Foreground="{BindingBg}"
Command="{x:Staticcontrols:BubblleControl.ClickCommand}"
CommandParameter="{BindingText}"
FontWeight="Normal">
<TextBlockText="{BindingText}"
TextAlignment="Center"
TextTrimming="CharacterEllipsis"
ToolTip="{BindingText}"/>
</Hyperlink>
</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:BubblleCanvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

</ResourceDictionary>

5) BubblleControlExample.xaml 代码如下;

  • TabItem随机 是自动设置位置和颜色;
  • TabItem自定义 可以自行定义展示的内容;
<UserControlx:Class="WPFDevelopers.Samples.ExampleViews.BubblleControlExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="450"d:DesignWidth="800">

<Grid>
<TabControl>
<TabItemHeader="随机">
<wpfdev:BubblleControlx:Name="MyBubblleControl"Click="BubblleControl_Click">
<wpfdev:BubblleControl.ItemsSource>
<x:ArrayType="sys:String">
<sys:String>WPF</sys:String>
<sys:String>ASP.NET</sys:String>
<sys:String>WinUI</sys:String>
<sys:String>WebAPI</sys:String>
<sys:String>Blazor</sys:String>
<sys:String>MAUI</sys:String>
<sys:String>Xamarin</sys:String>
<sys:String>WinForm</sys:String>
<sys:String>UWP</sys:String>
</x:Array>
</wpfdev:BubblleControl.ItemsSource>
</wpfdev:BubblleControl>
</TabItem>
<TabItemHeader="自定义">
<wpfdev:BubblleCanvasWidth="400"Height="400">
<Grid>
<GridWidth="60"
Height="60">
<EllipseFill="MediumSpringGreen"
Opacity=".4"/>
<EllipseStroke="MediumSpringGreen"
StrokeThickness=".8"/>
</Grid>
<TextBlockVerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="10,0">
<Hyperlink
Foreground="MediumSpringGreen"
FontWeight="Normal"
Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}">
<TextBlockText="WPF"
TextAlignment="Center"
TextTrimming="CharacterEllipsis"/>
</Hyperlink>
</TextBlock>
</Grid>
<Grid>
<GridWidth="60"
Height="60">
<EllipseFill="Brown"
Opacity=".4"/>
<EllipseStroke="Brown"
StrokeThickness=".8"/>
</Grid>
<TextBlockVerticalAlignmjavascriptent="Center"
HorizontalAlignment="Center"
Padding="10,0">
<Hyperlink
Foreground="Brown"
FontWeight="Normal"
Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}">
<TextBlockText="MAUI"
TextAlignment="Center"
TextTrimming="CharacterEllipsis"/>
</Hyperlink>
</TextBlock>
</Grid>
<Grid>
<GridWidth="60"
Height="60">
<EllipseFill="DeepSkyBlue"
Opacity=".4"/>
<EllipseStroke="DeepSkyBlue"
StrokeThickness=".8"/>
</Grid>
<TextBlockVerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="10,0">
<Hyperlink
Foreground="DeepSkyBlue"
FontWeight="Normal"
Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}">
<TextBlockText="Blazor"
TextAlignment="Center"
TextTrimming="CharacterEllipsis"/>
</Hyperlink>
</TextBlock>
</Grid>
</wpfdev:BubblleCanvas>
</TabItem>
</TabControl>

</Grid>
</UserControl>

6) BubblleControlExample.xaml.cs 代码如下;

usingSystem.Windows;
usingSystem.Windows.Controls;
usingSystem.Windows.Input;
usingWPFDevelopers.Samples.Helpers;

namespaceWPFDevelopers.Samples.ExampleViews
{
///<summary>
///BubbleControlExample.xaml的交互逻辑
///</summary>
publicpartialclassBubblleControlExample:UserControl
{
publicBubblleControlExample()
{
InitializeComponent();
}
publicICommandClickCommand=>newRelayCommand(delegate
{
WPFDevelopers.Minimal.Controls.MessageBox.Show("点击完成。");
});

privatevoidBubblleControl_Click(objectsender,System.Windows.RoutedEventArgse)
{
MessageBox.Show($"点击了“{MyBubblleControl.SelectedText}开发者”.","提示",MessageBoxButton.OK,MessageBoxImage.Information);
}
}
}

WPF模拟实现Gitee泡泡菜单的示例代码

以上就是WPF模拟实现Gitee泡泡菜单的示例代码的详细内容,更多关于WPF泡泡菜单的资料请关注我们其它相关文章!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜